Skip to content

ci: add cora AI code review#86

Merged
ajianaz merged 1 commit into
developfrom
feat/cora-review
May 31, 2026
Merged

ci: add cora AI code review#86
ajianaz merged 1 commit into
developfrom
feat/cora-review

Conversation

@ajianaz

@ajianaz ajianaz commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Changes

  • Add .github/actions/cora-review/ composite action

    • Downloads cora-cli binary from GitHub Releases (no Rust build needed)
    • Fetches LLM secrets (CORA_API_KEY, CORA_BASE_URL, CORA_MODEL) via Infisical OIDC
    • Runs cora review on PR diff β†’ SARIF output
    • Uploads SARIF to GitHub Code Scanning
    • Posts formatted PR comment (grouped by severity)
    • Blocks PR on error-level findings
  • Update .github/workflows/ci.yml

    • Add cora-review job (runs after check/fmt/clippy/test)
    • Only triggers on pull_request events
    • Required permissions: security-events, pull-requests, id-token

Requirements

  • Secret INFISICAL_IDENTITY_ID must be set in repo secrets βœ… (already configured)
  • Infisical project github-actions / env prod must have: CORA_API_KEY, CORA_BASE_URL, CORA_MODEL

Notes

  • Same action synced to cora-cli repo for consistency
  • Default version: v0.1.1 (configurable via cora-version input)
  • Default base branch: origin/develop (configurable via base-branch input)

Summary by CodeRabbit

  • Chores
    • Added automated AI code review integration to the CI pipeline that analyzes pull request changes, generates detailed reports, and provides summary comments.
    • Updated workflow permissions to support the new code review functionality.

- Add .github/actions/cora-review composite action (downloads cora-cli
  from GitHub Releases, fetches LLM secrets via Infisical OIDC, runs
  review on PR diff, uploads SARIF to Code Scanning, posts PR comment)
- Add cora-review job to CI workflow (runs after check/fmt/clippy/test
  pass, only on pull_request events)
- Add required permissions (security-events, pull-requests, id-token)
@coderabbitai

coderabbitai Bot commented May 31, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

This PR introduces automated AI-powered code review by adding a new composite GitHub Action that runs cora-cli on PR diffs, generates a SARIF report, uploads results to Code Scanning, posts a summary comment, and blocks the workflow if error-level issues are found. The action is then integrated into the CI pipeline with explicit permissions and job dependencies.

Changes

Cora AI Code Review Integration

Layer / File(s) Summary
Action interface and inputs
.github/actions/cora-review/action.yml
Declares composite action metadata and configurable inputs: base branch, severity, CLI version, Infisical credentials (identity, project, environment, domain), and GitHub token.
CLI setup and review execution
.github/actions/cora-review/action.yml
Detects runner OS architecture, downloads and extracts cora-cli release binary to /usr/local/bin, then executes cora review command with base branch and severity flags to generate SARIF output.
SARIF processing and result reporting
.github/actions/cora-review/action.yml
Uploads SARIF to GitHub Code Scanning; parses SARIF results and builds severity-grouped summary table; posts new or updates existing PR comment with status and issue details; performs blocking check by parsing SARIF for level: "error" and failing the workflow if any are found.
CI workflow permissions and job integration
.github/workflows/ci.yml
Adds explicit workflow-level permissions for contents (read), security-events (write), pull-requests (write), and id-token (write); defines cora-review job gated to pull_request events, depending on existing CI jobs, and invoking the local cora-review action with secrets.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Poem

🐰 A rabbit hops through CI gates,
With cora-cli at the readyβ€”
Code review flows through SARIF states,
Comments posted, workflow steady.
Error checks block the gate so tight,
Our tests now shine with AI light! ✨

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The title 'ci: add cora AI code review' directly and clearly describes the main change: adding a new CI component for AI code review.
Docstring Coverage βœ… Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cora-review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

πŸ” Cora AI Code Review

βœ… No issues found. Code looks good!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
.github/actions/cora-review/action.yml (2)

88-92: ⚑ Quick win

inputs.github-token is not actually applied to the Octokit client.

actions/github-script authenticates its github client via the github-token input (default ${{ github.token }}), not the GH_TOKEN env var. As written, the token passed into the action is ignored and the default job token is used. To honor the input, pass it through with.github-token.

♻️ Proposed fix
       uses: actions/github-script@v7
-      env:
-        GH_TOKEN: ${{ inputs.github-token }}
       with:
+        github-token: ${{ inputs.github-token }}
         script: |
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/cora-review/action.yml around lines 88 - 92, The
github-script step currently sets GH_TOKEN in env but does not pass the
inputs.github-token into the actions/github-script client, so the Octokit
instance will use the default job token; update the step that uses
actions/github-script@v7 to include with.github-token: ${{ inputs.github-token
}} (and remove or keep the GH_TOKEN env var as desired) so the `github` client
inside the `script` block is authenticated with the provided input rather than
the default token.

60-60: ⚑ Quick win

Use curl -fsSL so a failed download fails loudly.

Without --fail, an HTTP error (e.g., 404 for a missing release asset) returns a success exit code and pipes an HTML error page into tar. -S also restores error messages that -s suppresses.

♻️ Proposed fix
-        curl -sL "https://github.com/ajianaz/cora-cli/releases/download/${{ inputs.cora-version }}/${ASSET}-${{ inputs.cora-version }}.tar.gz" | tar xz -C /usr/local/bin cora
+        curl -fsSL "https://github.com/ajianaz/cora-cli/releases/download/${{ inputs.cora-version }}/${ASSET}-${{ inputs.cora-version }}.tar.gz" | tar xz -C /usr/local/bin cora
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/cora-review/action.yml at line 60, Replace the curl
invocation used to download the cora tarball so that HTTP errors cause a
non-zero exit; specifically update the command that pipes to tar (the line
invoking curl and tar extracting "cora") to use curl -fsSL instead of -sL (i.e.,
add --fail and --show-error flags) so failed downloads fail loudly and error
output is preserved.
πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/actions/cora-review/action.yml:
- Around line 176-185: The inline Python invoked in the ERRORS assignment always
raises IndentationError because its lines are indented; de-indent the script
passed to python3 -c so the first character of each Python line is at column 0
(or replace the inline -c snippet with a heredoc/EOF call) so the try/except can
execute and catch parse/runtime errors; specifically update the python3 -c
invocation that reads cora-results.sarif (the ERRORS=$(python3 -c "..." ...)
block) so the JSON-parsing try/except is not indented and returns the actual
count of results with level == "error" instead of always falling back to 0.

In @.github/workflows/ci.yml:
- Around line 13-17: Top-level workflow permissions are too broad: remove
elevated permissions (security-events: write, pull-requests: write, id-token:
write) from the global permissions block and restrict it to read-only (e.g.,
keep contents: read); ensure the specific job cora-review continues to declare
the needed write permissions in its own permissions block (the existing
cora-review permissions at lines 73-77) so only that job gets elevated rights.

---

Nitpick comments:
In @.github/actions/cora-review/action.yml:
- Around line 88-92: The github-script step currently sets GH_TOKEN in env but
does not pass the inputs.github-token into the actions/github-script client, so
the Octokit instance will use the default job token; update the step that uses
actions/github-script@v7 to include with.github-token: ${{ inputs.github-token
}} (and remove or keep the GH_TOKEN env var as desired) so the `github` client
inside the `script` block is authenticated with the provided input rather than
the default token.
- Line 60: Replace the curl invocation used to download the cora tarball so that
HTTP errors cause a non-zero exit; specifically update the command that pipes to
tar (the line invoking curl and tar extracting "cora") to use curl -fsSL instead
of -sL (i.e., add --fail and --show-error flags) so failed downloads fail loudly
and error output is preserved.
πŸͺ„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5bd552fb-a988-4fd6-88c0-acbe492088e3

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 0a21453 and 0f0646b.

πŸ“’ Files selected for processing (2)
  • .github/actions/cora-review/action.yml
  • .github/workflows/ci.yml

Comment on lines +176 to +185
ERRORS=$(python3 -c "
import json, sys
try:
data = json.load(open('cora-results.sarif'))
results = data.get('runs', [{}])[0].get('results', [])
errors = [r for r in results if r.get('level') == 'error']
print(len(errors))
except:
print(0)
" 2>/dev/null || echo "0")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚑ Quick win

Blocking check is non-functional: the inline Python always raises IndentationError.

The code passed to python3 -c is indented (10 leading spaces per line), so the first statement raises IndentationError: unexpected indent at parse time β€” before the try/except can run, so it cannot be caught. 2>/dev/null hides the error and || echo "0" forces ERRORS=0, meaning the PR is never blocked on error-level findings (the primary purpose of this action). De-indent the script to column 0.

πŸ› Proposed fix
-          ERRORS=$(python3 -c "
-          import json, sys
-          try:
-            data = json.load(open('cora-results.sarif'))
-            results = data.get('runs', [{}])[0].get('results', [])
-            errors = [r for r in results if r.get('level') == 'error']
-            print(len(errors))
-          except:
-            print(0)
-          " 2>/dev/null || echo "0")
+          ERRORS=$(python3 -c "
+import json
+try:
+    data = json.load(open('cora-results.sarif'))
+    results = data.get('runs', [{}])[0].get('results', [])
+    errors = [r for r in results if r.get('level') == 'error']
+    print(len(errors))
+except Exception:
+    print(0)
+" 2>/dev/null || echo "0")
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ERRORS=$(python3 -c "
import json, sys
try:
data = json.load(open('cora-results.sarif'))
results = data.get('runs', [{}])[0].get('results', [])
errors = [r for r in results if r.get('level') == 'error']
print(len(errors))
except:
print(0)
" 2>/dev/null || echo "0")
ERRORS=$(python3 -c "
import json
try:
data = json.load(open('cora-results.sarif'))
results = data.get('runs', [{}])[0].get('results', [])
errors = [r for r in results if r.get('level') == 'error']
print(len(errors))
except Exception:
print(0)
" 2>/dev/null || echo "0")
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/actions/cora-review/action.yml around lines 176 - 185, The inline
Python invoked in the ERRORS assignment always raises IndentationError because
its lines are indented; de-indent the script passed to python3 -c so the first
character of each Python line is at column 0 (or replace the inline -c snippet
with a heredoc/EOF call) so the try/except can execute and catch parse/runtime
errors; specifically update the python3 -c invocation that reads
cora-results.sarif (the ERRORS=$(python3 -c "..." ...) block) so the
JSON-parsing try/except is not indented and returns the actual count of results
with level == "error" instead of always falling back to 0.

Comment thread .github/workflows/ci.yml
Comment on lines +13 to +17
permissions:
contents: read
security-events: write
pull-requests: write
id-token: write

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚑ Quick win

Scope elevated permissions to the job, not the whole workflow.

security-events, pull-requests, and id-token: write at the top level are granted to every job (check, fmt, clippy, test, build) even though only cora-review needs them β€” and cora-review already declares its own permissions block (Lines 73-77). Restrict the workflow default to read-only to follow least privilege.

πŸ”’οΈ Proposed fix
 permissions:
   contents: read
-  security-events: write
-  pull-requests: write
-  id-token: write
🧰 Tools
πŸͺ› zizmor (1.25.2)

[warning] 15-15: overly broad permissions (excessive-permissions): security-events: write is overly broad at the workflow level

(excessive-permissions)


[error] 16-16: overly broad permissions (excessive-permissions): pull-requests: write is overly broad at the workflow level

(excessive-permissions)


[error] 17-17: overly broad permissions (excessive-permissions): id-token: write is overly broad at the workflow level

(excessive-permissions)

πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 13 - 17, Top-level workflow
permissions are too broad: remove elevated permissions (security-events: write,
pull-requests: write, id-token: write) from the global permissions block and
restrict it to read-only (e.g., keep contents: read); ensure the specific job
cora-review continues to declare the needed write permissions in its own
permissions block (the existing cora-review permissions at lines 73-77) so only
that job gets elevated rights.

@ajianaz
ajianaz merged commit 2d6715b into develop May 31, 2026
7 of 8 checks passed
@ajianaz
ajianaz deleted the feat/cora-review branch May 31, 2026 01:16
ajianaz added a commit that referenced this pull request Jun 4, 2026
* feat: add uteke-status pi extension

Pi extension that shows uteke memory stats in the footer status bar:
- 🧠 uteke: πŸ”₯3 hot | 🟑0 warm | ❄️0 cold (65 total)
- Auto-refreshes after memory operations (remember, forget, import, cleanup)
- Registers /uteke-stats command to manually refresh
- Registers /uteke command for quick stats/aging/doctor/tags

Install: copy to ~/.pi/agent/extensions/uteke-status/ or use pi install

* feat(uteke-status): v2 β€” cross-namespace stats + system prompt injection

- Query SQLite directly for cross-namespace totals (was only showing
  default namespace before)
- Add proper spacing between icons and numbers
- Inject system prompt via before_agent_start to remind agent to use
  uteke actively (remember, recall, search, save summaries)
- Simplified: removed /uteke command, kept /uteke-stats
- Uses sqlite3 CLI (pre-installed on macOS/Linux)

* feat: bulk memory operations (#43)

- forget <id> β€” now prompts for confirmation [y/N]
- forget --tag <tag> β€” delete all memories with a tag
- forget --cold β€” delete all cold (>30d or never accessed) memories
- forget --all β€” delete ALL memories in namespace
- All bulk ops require --confirm flag to execute
- Added BulkDeleteResult type with deleted count + IDs
- Added store methods: bulk_delete_by_tag, bulk_delete_cold,
  bulk_delete_all, count_by_tag
- Added Uteke methods: bulk_forget_by_tag, bulk_forget_cold,
  bulk_forget_all, store()

* ci: add cora AI code review composite action (#86)

- Add .github/actions/cora-review composite action (downloads cora-cli
  from GitHub Releases, fetches LLM secrets via Infisical OIDC, runs
  review on PR diff, uploads SARIF to Code Scanning, posts PR comment)
- Add cora-review job to CI workflow (runs after check/fmt/clippy/test
  pass, only on pull_request events)
- Add required permissions (security-events, pull-requests, id-token)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): comment default, SARIF upload optional (#87)

- Post PR comment: always runs (default behavior)
- SARIF upload: opt-in via upload-sarif: 'true' input
- SARIF upload failure: continue-on-error (never blocks)
- Blocking: only error-level findings block merge

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): resolve latest version via API before download (#89)

GitHub release download URL doesn't support 'latest' tag.
Resolve to actual tag via GitHub API first.

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat: smooth namespace switching and defaults (#82)

* feat: add uteke-status pi extension

Pi extension that shows uteke memory stats in the footer status bar:
- 🧠 uteke: πŸ”₯3 hot | 🟑0 warm | ❄️0 cold (65 total)
- Auto-refreshes after memory operations (remember, forget, import, cleanup)
- Registers /uteke-stats command to manually refresh
- Registers /uteke command for quick stats/aging/doctor/tags

Install: copy to ~/.pi/agent/extensions/uteke-status/ or use pi install

* feat(uteke-status): v2 β€” cross-namespace stats + system prompt injection

- Query SQLite directly for cross-namespace totals (was only showing
  default namespace before)
- Add proper spacing between icons and numbers
- Inject system prompt via before_agent_start to remind agent to use
  uteke actively (remember, recall, search, save summaries)
- Simplified: removed /uteke command, kept /uteke-stats
- Uses sqlite3 CLI (pre-installed on macOS/Linux)

* feat: bulk memory operations (#43)

- forget <id> β€” now prompts for confirmation [y/N]
- forget --tag <tag> β€” delete all memories with a tag
- forget --cold β€” delete all cold (>30d or never accessed) memories
- forget --all β€” delete ALL memories in namespace
- All bulk ops require --confirm flag to execute
- Added BulkDeleteResult type with deleted count + IDs
- Added store methods: bulk_delete_by_tag, bulk_delete_cold,
  bulk_delete_all, count_by_tag
- Added Uteke methods: bulk_forget_by_tag, bulk_forget_cold,
  bulk_forget_all, store()

* feat: smooth namespace switching and defaults (#45)

- Add `uteke namespace list` β€” list all namespaces with memory counts
- Add `uteke namespace stats <name>` β€” show stats for a namespace
- Add `uteke namespace switch <name>` β€” set default namespace in config
- Implement layered namespace resolution: CLI flag > env > config > default
- Fix broken `resolve_namespace` that referenced undefined variable
- Support UTEKE_NAMESPACE env var for per-session defaults
- Config file default_namespace persists across sessions

* feat: daemon/server mode for warm recall <50ms (#83)

* feat: add uteke-status pi extension

Pi extension that shows uteke memory stats in the footer status bar:
- 🧠 uteke: πŸ”₯3 hot | 🟑0 warm | ❄️0 cold (65 total)
- Auto-refreshes after memory operations (remember, forget, import, cleanup)
- Registers /uteke-stats command to manually refresh
- Registers /uteke command for quick stats/aging/doctor/tags

Install: copy to ~/.pi/agent/extensions/uteke-status/ or use pi install

* feat(uteke-status): v2 β€” cross-namespace stats + system prompt injection

- Query SQLite directly for cross-namespace totals (was only showing
  default namespace before)
- Add proper spacing between icons and numbers
- Inject system prompt via before_agent_start to remind agent to use
  uteke actively (remember, recall, search, save summaries)
- Simplified: removed /uteke command, kept /uteke-stats
- Uses sqlite3 CLI (pre-installed on macOS/Linux)

* feat: bulk memory operations (#43)

- forget <id> β€” now prompts for confirmation [y/N]
- forget --tag <tag> β€” delete all memories with a tag
- forget --cold β€” delete all cold (>30d or never accessed) memories
- forget --all β€” delete ALL memories in namespace
- All bulk ops require --confirm flag to execute
- Added BulkDeleteResult type with deleted count + IDs
- Added store methods: bulk_delete_by_tag, bulk_delete_cold,
  bulk_delete_all, count_by_tag
- Added Uteke methods: bulk_forget_by_tag, bulk_forget_cold,
  bulk_forget_all, store()

* feat: smooth namespace switching and defaults (#45)

- Add `uteke namespace list` β€” list all namespaces with memory counts
- Add `uteke namespace stats <name>` β€” show stats for a namespace
- Add `uteke namespace switch <name>` β€” set default namespace in config
- Implement layered namespace resolution: CLI flag > env > config > default
- Fix broken `resolve_namespace` that referenced undefined variable
- Support UTEKE_NAMESPACE env var for per-session defaults
- Config file default_namespace persists across sessions

* feat: daemon/server mode for warm recall <50ms (#54)

- Add uteke-server crate with HTTP API (tiny_http)
- Endpoints: /health, /remember, /recall, /search, /list, /forget, /stats, /namespaces
- Namespace support on all endpoints via JSON body
- CORS headers for cross-origin access
- Graceful shutdown on SIGINT (saves index, closes DB)
- Config: [server] section in uteke.toml (host, port, enabled)
- Benchmark: recall ~41ms (vs 2600ms CLI cold start)
- Binary: uteke-serve --host 127.0.0.1 --port 8767

* feat: auto-forget, temporal facts & contradiction detection (#51) (#84)

- Add temporal metadata: deprecated, valid_from, valid_until, memory_type
- Memory types: fact, procedure, preference, decision, context
- Contradiction detection on remember (--detect-contradiction flag)
  - Auto-deprecates old conflicting memories via vector similarity
  - Threshold calibrated for embeddinggemma-q4 model
- Prune command: uteke prune --ttl 30d --dry-run
  - Removes deprecated memories older than TTL
  - Dry-run mode for safe preview
- remember --type flag for memory classification
- DB migration: auto-adds new columns to existing stores
- All 22 tests pass

* feat: knowledge graph consolidation & deduplication (#52) (#85)

- Add consolidate command: uteke consolidate --threshold 0.90 --dry-run
- Detect near-duplicate memories via cosine similarity
- Merge duplicates: keeps newer, removes older, updates vector index
- Dry-run mode shows duplicate pairs without modifying store
- Add SimilarPair and ConsolidationResult types
- cosine_similarity helper for O(nΒ²) pairwise comparison
- Threshold configurable (default 0.90, recommend 0.60-0.70 for small models)
- All 22 tests pass

* feat: CLI auto-routes to server when enabled (#90)

- CLI detects running uteke-serve via HTTP health check
- When server.available, routes remember/recall/search/list/stats/forget via HTTP
- Recall latency: 21ms (vs 946ms CLI cold start) β€” 45x faster
- Fallback: if server not running, CLI works as before (cold start)
- Config: [server] enabled = true in uteke.toml
- All 22 tests pass

* chore: prepare v0.0.4 release (#91)

* chore: prepare v0.0.4 release

- Bump version 0.0.3 β†’ 0.0.4
- CHANGELOG: add v0.0.4 with all new features
- README: add server mode, consolidate, prune, namespace switch, fix 256d embedding
- CLI reference docs: add forget bulk, consolidate, prune, namespace, server mode
- Configuration docs: add server section, namespace resolution
- Roadmap: add v0.0.4 completed items, update next/future
- Multi-agent docs: add namespace switching section
- Release workflow: build both uteke + uteke-serve, updated release notes

* chore: fix clippy warnings, add cora review config

- Fix all clippy warnings across workspace (uteke-cli, uteke-core, uteke-server)
- Fix rustfmt issues across workspace
- Remove unused Arc import in uteke-server
- Fix cosine_similarity placement after test module in uteke-core
- Fix config loop indexing in uteke-cli
- Add .cora.yaml with custom provider (glm-5.1)
- Install cora pre-commit hook (warn mode)
- Fix strip fallback in release workflow
- Add config migration docs to website

* fix(ci): cora review exit code handling (#92)

- Update cora-cli to v0.1.2 (fixes spurious exit code 2)
- Add || true to cora review step so SARIF is always generated
- Blocking check still works via SARIF level analysis

* fix(ci): proper cora review error handling (#93)

- Replace || true with explicit exit code handling
- Exit code 0 (clean) and 2 (findings found) both proceed
- Other exit codes show ::warning with stderr log
- Empty SARIF produces warning instead of silent failure
- No more 2>/dev/null β€” errors are visible when unexpected

* fix(ci): dynamic release notes from CHANGELOG.md (#94)

- Extract changelog section via awk instead of hardcoded body
- Filter out bottom comparison links
- Printf-based footer to avoid YAML indentation leaking
- Warning annotation if CHANGELOG section not found
- No more manual workflow edits per release

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat(core): add UTEKE_HOME env var for custom data directory (#106)

- Add public uteke_home() in uteke-core β€” resolves data directory
- UTEKE_HOME set: uses that path directly (e.g. /data)
- UTEKE_HOME unset: falls back to ~/.uteke (zero breaking change)
- engine.rs: model path uses uteke_home() instead of dirs::home_dir()
- lib.rs: doctor model check uses uteke_home()
- uteke-server: DB path uses uteke_core::uteke_home()
- Remove unused dirs dependency from uteke-server

Closes #95

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* chore(docs): update roadmap with v0.0.5-v0.0.7 milestones (#103)

- v0.0.5: Docker & Deployment (5 issues)
- v0.0.6: Network & Auth (4 issues)
- v0.0.7: Cloud MVP (future)
- Backlog reorganized (6 items)
- Color-coded sections per version
- Descriptions for each milestone

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat(server): read uteke.toml config + smart server fallback (#107)

* feat(server): read uteke.toml config, default host 0.0.0.0

Server now reads [server] section from uteke.toml:
- Layered resolution: uteke_home/uteke.toml β†’ cwd/.uteke/uteke.toml
- Default host changed: 127.0.0.1 β†’ 0.0.0.0 (Docker-compatible)
- CLI --host/--port override config values
- Added toml dependency for config parsing

Also fixes smart server fallback (#104):
- CLI commands not supported via HTTP auto-fallback to local store
- No more error 'This command requires local store'
- Log message: 'Command not supported via server, using local store'

Closes #96
Closes #104

* fix(server): resolve type mismatch in load_uteke_toml path array

* style(server): apply cargo fmt

---------

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat(server): API parity β€” expanded remember, GET /memory endpoint (#108)

Expanded POST /remember to accept optional fields:
- type: fact, procedure, preference, decision, context
- valid_from, valid_until: temporal facts
- detect_contradiction: auto-deprecate conflicting memories

Added GET /memory?id=<uuid> endpoint:
- Returns full memory by ID
- 404 if not found

Updated --help to document new endpoint.

Closes #105

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat(docker): add multi-stage Dockerfile and .dockerignore (#109)

Dockerfile:
- Stage 1: download release binary + embedding model from HuggingFace
- Stage 2: runtime only (debian:bookworm-slim + binaries + model)
- ENV UTEKE_HOME=/data for volume mount
- EXPOSE 8767, ENTRYPOINT uteke-serve
- ARG VERSION and TARGET for build flexibility

.dockerignore:
- Excludes .git, target, node_modules, website, docs

Closes #97

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat(ci): Docker image build & push on release (#110)

* feat(docker): add multi-stage Dockerfile and .dockerignore

Dockerfile:
- Stage 1: download release binary + embedding model from HuggingFace
- Stage 2: runtime only (debian:bookworm-slim + binaries + model)
- ENV UTEKE_HOME=/data for volume mount
- EXPOSE 8767, ENTRYPOINT uteke-serve
- ARG VERSION and TARGET for build flexibility

.dockerignore:
- Excludes .git, target, node_modules, website, docs

Closes #97

* feat(ci): add Docker image build & push to release workflow

Multi-arch Docker build (linux/amd64 + linux/arm64):
- Triggered after release job completes
- Builds from Dockerfile with VERSION and TARGET build args
- Pushes to ghcr.io/ajianaz/uteke with semver tags + latest
- Uses GITHUB_TOKEN for GHCR auth (no new secrets needed)
- QEMU + buildx for cross-platform

Closes #99

---------

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* chore: prepare v0.0.5 release (#111)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(docker): remove pinned digest and update default version (#112)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(docker): remove pinned digest from runtime stage too (#113)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(docker): add curl retry and timeout for CI reliability (#114)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): move downloads to host runner β€” buildx cannot access network (#115)

Buildx docker-container driver cannot reach github.com/huggingface.co,
causing consistent curl exit code 1. Move all downloads to CI host steps
and pass files via Docker context COPY instead.

- Dockerfile: COPY binaries/ and models/ from context, select by TARGETARCH
- release.yml: download step before build, single multi-platform push

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): use build artifacts + lazy runtime model download (#116)

Primary: Docker job now depends on build-release (not release), gets
binaries via actions/download-artifact@v4 β€” no curl to github.com.

Fallback: Entrypoint checks if model exists at startup, downloads if
missing β€” works even if CI model bake step fails.

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): find artifacts recursively β€” merge-multiple adds subdir (#117)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix(ci): remove --strip-components from tar extraction (#118)

The tar.gz archives contain uteke + uteke-serve at root level
(no directory prefix). --strip-components=1 was stripping the
filenames themselves, resulting in empty extraction.

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* refactor: adopt cora-review v2 β€” standalone workflow + hardened action (#119)

- Extract cora-review into its own workflow (.github/workflows/cora-review.yml)
  with dedicated concurrency group, 10-minute timeout, and scoped permissions
- Harden action.yml: pinned action SHAs, checksum verification on cora-cli
  download, retry logic for version resolution, empty-result handling
- Remove cora-review job and elevated permissions from ci.yml
  (CI pipeline now contains only Rust check/fmt/clippy/test/build)

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* fix: v0.0.6 patch & hardening (#146)

* fix: v0.0.6 patch & hardening β€” CI, Docker, API correctness

Closes #122, #123 (already done on develop), #124, #125, #126, #145

- ci.yml, release.yml: add FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 (#125)
- ci.yml, release.yml: remove unused musl-tools install (#145)
- release.yml: remove musl-tools apt step (#145)
- Dockerfile: add non-root USER directive with uteke user (#126)
- Dockerfile: create /data with correct ownership before USER switch
- types.rs: add #[serde(skip_serializing)] on Memory.embedding (#124)
- lib.rs: persist vector index after import() completes (#124)
- vector.rs: improve expect() panic message with dims and root cause hint (#124)
- .github/dependabot.yml: add Dependabot for cargo, github-actions, docker (#122)

* fix(test): update test_memory_types_serialization for skip_serializing embedding

The embedding field now uses #[serde(skip_serializing)], so the test
verifies that embedding is excluded from JSON output and that
deserialization produces an empty embedding (expected β€” embeddings are
populated programmatically via ONNX, not from JSON).

* fix: add serde(default) to skip_serializing embedding

skip_serializing without default causes deserialization error when
embedding field is missing from JSON. Adding default allows graceful
fallback to empty vec.

* release: v0.0.6 β€” patch & hardening

- CHANGELOG: add v0.0.6 entry, reorder all versions chronologically, consolidate link refs
- Cargo.toml: bump 0.0.5 β†’ 0.0.6

---------

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat: v0.0.7 β€” core stability (#157)

* feat: v0.0.7 β€” core stability (tag refactor, config wiring, tests)

#120 Tag storage: refactor all LIKE-based tag queries to json_each()
  - list(), unique_tags(), tags_with_counts(), count_tag(), rename_tag(),
    delete_tag(), bulk_delete_by_tag(), count_by_tag
  - tags_with_counts: N+1 β†’ single GROUP BY query
  - unique_tags: in-Rust JSON parse β†’ SQL json_each()
  - 11 new tag-related tests

#127 Config wiring: pass tier thresholds from config to core
  - Add TierConfig struct (hot_days, warm_days, hot_boost)
  - Uteke::open_with_tier() accepts custom tier config
  - MemoryTier::from_last_accessed() now takes configurable thresholds
  - main.rs passes config.tier.* to core
  - 7 new config tests (merge_from_file_all_sections, expand_tilde, etc.)

#129 Test coverage: +44 tests (22 β†’ 66 in store, 8 β†’ 25 in lib, 4 β†’ 15 in config)
  - Bulk operations: bulk_delete_by_tag, bulk_delete_cold, bulk_delete_all
  - Store operations: rename_tag, delete_tag, deprecate, tier_counts
  - Edge cases: search_content, find_aged, find_similar, pagination
  - Double insert, namespace isolation, empty results

#140 Namespace CLI: already implemented (NamespaceCommands::List)

Closes #120, #127, #129, #140

* fix: update old tests for new MemoryTier::from_last_accessed() signature

- Pass hot_days=7, warm_days=30 to old tier tests
- Remove dead count_tag() method (replaced by count_by_tag)

* fix: update all callers for tier_counts/bulk_delete_cold new signatures

Old tests called tier_counts(None) and bulk_delete_cold(None) with
1 arg, but sub-agent changed signatures to accept hot_days/warm_days.
Updated 5 test call sites.

* fix: correct test_path_in_memory and test_search_content_edge_cases

- test_path_in_memory: rusqlite may return Some for :memory: DB path
- test_search_content_edge_cases: SQLite LIKE is case-insensitive by default

* docs: fix configuration section in README (#128)

- Fix config search paths: .uteke/uteke.toml + ~/.uteke/uteke.toml
- Fix config format: proper TOML sections matching actual Config struct
- Remove non-existent --config flag from CLI reference
- Add all config sections: store, embedding, tier, logging, server

---------

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* release: v0.0.7 β€” core stability (#158)

CHANGELOG: add v0.0.7 entry with all changes
Cargo.toml: bump 0.0.6 β†’ 0.0.7

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* chore(deps): consolidate Dependabot bumps β€” 10 deps in 1 PR (#159)

Cargo deps:
- thiserror 1 β†’ 2 (API unchanged for our usage)
- dirs 5 β†’ 6 (home_dir() unchanged)
- toml 0.8 β†’ 1 (from_str() unchanged)
- uuid 1.23.1 β†’ 1.23.2 (patch)

GitHub Actions:
- docker/login-action v3 β†’ v4
- docker/metadata-action v5 β†’ v6
- actions/upload-artifact v4 β†’ v7
- Infisical/secrets-action v1.0.9 β†’ v1.0.16
- actions/setup-node v4 β†’ v6
- cloudflare/wrangler-action v3 β†’ v4

All changes reviewed β€” no breaking API impact for our usage.

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

* feat: release branch setup β€” main as release-only mirror (#168)

- Add install.sh at root with SHA256 checksum verification
- Add sync-main job to release.yml (develop β†’ main on every v* tag)
- Add SHA256 checksums generation to release job
- Enable Cora Review on PRs to main branch
- Update INSTALL.md to reference main/install.sh
- Update release notes template to use main/install.sh

Clones cora-cli #154/#155/#156 release branch pattern.

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>

---------

Co-authored-by: CTO Hermes <cto-hermes@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant