Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
05032c7
hppocampus
khezen Jul 23, 2026
6bdbafb
improve trajectory truncation
khezen Jul 23, 2026
5173433
hippocampus: fix truncation and remove useless stuff
khezen Jul 23, 2026
b6089de
hippocampus: fix truncation and remove useless stuff
khezen Jul 23, 2026
d5b5c02
hippocampus
khezen Jul 23, 2026
0823bde
add storage to hippocampus
khezen Jul 24, 2026
d53979f
add storage to hippocampus
khezen Jul 24, 2026
9ab23a6
add storage to hippocampus
khezen Jul 24, 2026
ec588a8
add storage to hippocampus
khezen Jul 24, 2026
8782c15
wip
khezen Jul 26, 2026
1e2dc8c
wip
khezen Jul 27, 2026
df30382
wip
khezen Jul 27, 2026
f30ae81
wip
khezen Jul 27, 2026
6510c81
wip
khezen Jul 27, 2026
efaa08c
typo
khezen Jul 27, 2026
28690eb
typo
khezen Jul 27, 2026
7f1897d
cfg
khezen Jul 27, 2026
4389a5f
cfg
khezen Jul 27, 2026
4660beb
cfg
khezen Jul 27, 2026
1b150c4
cfg
khezen Jul 27, 2026
e8d29be
cfg
khezen Jul 27, 2026
0bd88ab
cfg
khezen Jul 27, 2026
51806fe
cfg
khezen Jul 28, 2026
1acdbad
wip
khezen Aug 4, 2026
ee6fe45
wip
khezen Aug 6, 2026
7b3676e
wip
khezen Aug 6, 2026
f034219
remove .kilo
khezen Aug 6, 2026
d0fe81e
remove .kilo
khezen Aug 6, 2026
217e13f
wip
khezen Aug 6, 2026
9c7a6aa
wip
khezen Aug 6, 2026
26b83fa
wip
khezen Aug 7, 2026
99b95e4
treesitter upgrade
khezen Aug 7, 2026
56aa110
treesitter upgrade
khezen Aug 7, 2026
3f4929a
wip
khezen Aug 8, 2026
e7d7e28
wip
khezen Aug 8, 2026
abd8f11
wip
khezen Aug 9, 2026
e7daacc
wip
khezen Aug 9, 2026
592090b
wip
khezen Aug 9, 2026
32a92d3
wip
khezen Aug 9, 2026
6a7bce5
wip
khezen Aug 9, 2026
88a335f
wip
khezen Aug 9, 2026
92f181a
wip
khezen Aug 10, 2026
33a7777
wip
khezen Aug 10, 2026
6f8ff10
wip
khezen Aug 10, 2026
5cbfcb2
wip
khezen Aug 10, 2026
0b54b33
wip
khezen Aug 10, 2026
0bff96f
wip
khezen Aug 10, 2026
7611884
wip
khezen Aug 10, 2026
6d1c9ef
wip
khezen Aug 11, 2026
0babecb
wip
khezen Aug 11, 2026
0f80165
wip
khezen Aug 11, 2026
330c154
wip
khezen Aug 11, 2026
ace3672
wip
khezen Aug 11, 2026
f8d5f3a
wip
khezen Aug 11, 2026
8287d26
wip
khezen Aug 11, 2026
36f0de2
wip
khezen Aug 11, 2026
dc5cd8b
Revert "wip"
khezen Aug 12, 2026
6c25150
wip
khezen Aug 12, 2026
95a2cd3
wip
khezen Aug 16, 2026
a47a5cc
wip
khezen Aug 16, 2026
9488d49
wip
khezen Aug 16, 2026
db7ae23
wip
khezen Aug 16, 2026
d01c802
wip
khezen Aug 16, 2026
6620cdb
wip
khezen Aug 16, 2026
d527745
wip
khezen Aug 16, 2026
de9b6e8
deny more
khezen Aug 17, 2026
7b64d76
wip
khezen Aug 17, 2026
98f0a1f
add access verification
khezen Aug 17, 2026
221ec66
wip
khezen Aug 17, 2026
810efaf
wip
khezen Aug 17, 2026
3cc7f48
wip
khezen Aug 17, 2026
d9ea599
wip
khezen Aug 17, 2026
73a7fbb
wip
khezen Aug 17, 2026
ce33ba0
wip
khezen Aug 17, 2026
7abcf28
wip
khezen Aug 17, 2026
a467799
wip
khezen Aug 17, 2026
ff47984
wip
khezen Aug 17, 2026
8c7eaea
wip
khezen Aug 17, 2026
1a5c5ef
release
khezen Aug 17, 2026
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
139 changes: 122 additions & 17 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,20 @@ DEFAULT_MODEL=anthropic/claude-opus-4-6
# but not deep reasoning. Recommended: anthropic/claude-sonnet-4-5-20250929
# or equivalent.
#
# Cheap (SUMMARIZATION_MODEL): PR summary generation. Simple synthesis.
# Cheap (SUMMARY_MODEL): PR summary generation. Simple synthesis.
# Recommended: anthropic/claude-haiku-4-5-20251001 or equivalent.
#
# Mid-tier (MEMORY_DISTILLER_MODEL / MEMORY_CARTOGRAPHER_MODEL): Memory
# reflection — summarizing a trajectory and curating the context memory.
# Requires nuance.
# Recommended: anthropic/claude-sonnet-4-5-20250929 or equivalent.
#
# By default, all models fall back to DEFAULT_MODEL. To optimize costs:
# EXTRACTION_MODEL=anthropic/claude-sonnet-4-5-20250929
# SUMMARIZATION_MODEL=anthropic/claude-haiku-4-5-20251001
# SUMMARY_MODEL=anthropic/claude-haiku-4-5-20251001
# MEMORY_DISTILLER_MODEL=anthropic/claude-sonnet-4-5-20250929
# MEMORY_CARTOGRAPHER_MODEL=anthropic/claude-sonnet-4-5-20250929


# =============================================================================
# Default Settings
Expand All @@ -116,12 +124,23 @@ DEFAULT_MODEL=anthropic/claude-opus-4-6
# Falls back to DEFAULT_MODEL if not set
# EXTRACTION_MODEL=anthropic/claude-sonnet-4-5-20250929

# DEFAULT_MAX_ITERS=3
# DEFAULT_MAX_CONTEXT_SIZE=50000
# Limits LLM reasoning verbosity (helps prevent JSONAdapter failures)
# DEFAULT_MAX_REASONING_TOKENS=1024
# Lower = more deterministic JSON output
# DEFAULT_TEMPERATURE=0.1
# DEFAULT_MAX_ITERS=10
# Provider reasoning budget: minimal | low | medium | high
# DEFAULT_REASONING_EFFORT=medium
# DEFAULT_TEMPERATURE=0.2

# Output token budget for a single completion (default: 64000). This is an OUTPUT
# ceiling, not a context window, and reasoning/thinking tokens are charged against
# it — so keep it well above the expected answer size while DEFAULT_REASONING_EFFORT
# is set. codespy always sends an explicit value: without one LiteLLM silently falls
# back to its own 4096 default and truncates responses mid-answer (DSPy warns
# "LM response was truncated ... max_tokens=None").
# The value is clamped down to each model's real output ceiling before use, so a
# generous setting stays valid on smaller models; models LiteLLM doesn't know
# (Ollama, custom endpoints) receive it unchanged.
# NOTE: LiteLLM also reads DEFAULT_MAX_TOKENS for its own internal fallback, so
# setting this aligns both layers.
# DEFAULT_MAX_TOKENS=64000

# Global LLM reliability settings
# Number of retries for LLM API calls
Expand All @@ -132,6 +151,73 @@ DEFAULT_MODEL=anthropic/claude-opus-4-6
# Enable provider-side prompt caching (reduces latency and costs)
# ENABLE_PROMPT_CACHING=true

# =============================================================================
# Memory (Hippocampus)
# =============================================================================
# Hippocampus lets scope-based agents (scope, code_review, doc, supply_chain)
# consolidate their run into a ContextMemory and persist it as an Episode.
# Save-only for now (no loading). Disabled by default per-signature — see
# the per-signature MEMORY_* settings below.
#
# Episodes are written to:
# global/episodic/<repo>/<scope-subroot>/codespy-<task>-<timestamp>.json
# under MEMORY_ROOT (filesystem) or MEMORY_S3_BUCKET (s3).

# Storage backend: filesystem or s3 (default: filesystem)
# MEMORY_BACKEND=filesystem

# Filesystem backend
# MEMORY_ROOT=~/.cache/codespy/memory

# S3 backend (used when MEMORY_BACKEND=s3)
# MEMORY_S3_BUCKET=my-bucket
# Falls back to AWS_REGION if not set
# MEMORY_S3_REGION=us-east-1
# For MinIO / S3-compatible endpoints
# MEMORY_S3_ENDPOINT_URL=https://minio.example.com

# Reflection defaults — overridable per-signature via <SIGNATURE>_MEMORY_*
# MEMORY_DEFAULT_ENABLED=false
# 0 = reflect once at end_episode
# MEMORY_DEFAULT_MAX_REFLECTS=0
#
# Four independent token budgets, most to least cost-sensitive:
#
# 1. Ceiling on the rendered ContextMemory. This is the persisted artifact, and it is
# prepended to every agent iteration, so it is re-sent ~DEFAULT_MAX_ITERS times
# per scope. Divided by MEMORY_DEFAULT_MAX_CONTEXT_ITEM_TOKENS it gives the memory's item
# capacity (8192 / 410 ~= 19 items).
# MEMORY_DEFAULT_MAX_CONTEXT_MEMORY_TOKENS=8192
# 2. Budget for a SINGLE context-memory item, given to the Distiller and the
# Cartographer as a prompt input so no one item eats the whole memory. Soft limit
# (expressed to the LLM, not enforced — truncating an item could corrupt an exact
# constant). Lower it for more, terser items; raise it for fewer, richer ones.
# MEMORY_DEFAULT_MAX_CONTEXT_ITEM_TOKENS=410
# 3. Cap on the trajectory fed to the Distiller. Tool-using agents can produce
# 100k+ token trajectories and TwoStepAdapter sends the value twice, so keep this
# to ~5-10% of the reflection model's context window. Unset = full trajectory
# (unbounded — not recommended for tool-using agents).
# MEMORY_DEFAULT_MAX_TRAJECTORY_TOKENS=8192
# 4. Cap on the serialized agent inputs used as the reflection "question". Without
# it, every input field is sent in full (for code review, the complete patch of
# every changed file). Unset = unbounded.
# MEMORY_DEFAULT_MAX_QUESTION_TOKENS=2048

# LLM settings for the reflection modules. The Distiller summarizes a trajectory;
# the Cartographer curates the context memory. Both are compact summarize/curate
# tasks, so a cheaper tier than code review usually suffices.
# Each falls back to the corresponding DEFAULT_* value when unset.
# MEMORY_DISTILLER_MODEL=anthropic/claude-haiku-4-5-20251001
# MEMORY_DISTILLER_REASONING_EFFORT=low
# MEMORY_DISTILLER_TEMPERATURE=1
# MEMORY_DISTILLER_MAX_TOKENS=64000

# MEMORY_CARTOGRAPHER_MODEL=anthropic/claude-haiku-4-5-20251001
# MEMORY_CARTOGRAPHER_REASONING_EFFORT=low
# MEMORY_CARTOGRAPHER_TEMPERATURE=1
# MEMORY_CARTOGRAPHER_MAX_TOKENS=64000


# =============================================================================
# Output Settings
# =============================================================================
Expand Down Expand Up @@ -159,31 +245,50 @@ DEFAULT_MODEL=anthropic/claude-opus-4-6
# - DOC (compares patches against documentation)
# - SCOPE (code scope detection)
# - SUPPLY_CHAIN (supply chain security analysis)
# - SUMMARIZATION (PR summary generation)
# - SUMMARY (PR summary generation)
#
# Available settings per signature:
# - ENABLED (true/false)
# - MAX_ITERS (integer)
# - MODEL (LiteLLM model string)
# - MAX_CONTEXT_SIZE (integer)
# - MAX_REASONING_TOKENS (integer) - Limits reasoning verbosity
# - TEMPERATURE (float) - Lower = more deterministic output
# - REASONING_EFFORT (minimal|low|medium|high) - Provider reasoning budget
# - TEMPERATURE (float) - Must be 1 while reasoning is enabled
# - MAX_TOKENS (integer) - Output token budget (unset -> DEFAULT_MAX_TOKENS)
# - MEMORY_ENABLED (true/false) - Hippocampus memory (unset -> MEMORY_DEFAULT_ENABLED)
# - MEMORY_MAX_REFLECTS (integer) - Max mid-run reflections (0 = reflect once at end)

# Examples:
# CODE_REVIEW_ENABLED=true
# CODE_REVIEW_MAX_ITERS=10
# CODE_REVIEW_MODEL=anthropic/claude-sonnet-4-5-20250929
# CODE_REVIEW_MAX_REASONING_TOKENS=512
# CODE_REVIEW_TEMPERATURE=0.1
# CODE_REVIEW_REASONING_EFFORT=high
# CODE_REVIEW_TEMPERATURE=1
# CODE_REVIEW_MAX_TOKENS=64000

# CODE_REVIEW_MEMORY_ENABLED=true
# CODE_REVIEW_MEMORY_MAX_REFLECTS=1

# SUPPLY_CHAIN_ENABLED=true
# When true: scans ALL artifacts (Dockerfiles, etc.) and manifests
# When false (default): only scans artifacts/manifests modified in the MR
# SUPPLY_CHAIN_SCAN_UNCHANGED=false
# SUPPLY_CHAIN_MEMORY_ENABLED=true
# SUPPLY_CHAIN_MEMORY_MAX_REFLECTS=1

# DOC_ENABLED=true
# DOC_MODEL=anthropic/claude-sonnet-4-5-20250929
# DOC_MEMORY_ENABLED=true
# DOC_MEMORY_MAX_REFLECTS=1

# SCOPE_ENABLED=true
# SCOPE_MAX_ITERS=10
# SCOPE_MAX_REASONING_TOKENS=1024
# SCOPE_REASONING_EFFORT=low
# SCOPE_MAX_TOKENS=64000
# SCOPE_MEMORY_ENABLED=true
# SCOPE_MEMORY_MAX_REFLECTS=1

# SUMMARY_ENABLED=true
# SUMMARY_MODEL=anthropic/claude-haiku-4-5-20251001
# SUMMARY_MEMORY_ENABLED=true
# SUMMARY_MEMORY_MAX_REFLECTS=1

# SUMMARIZATION_ENABLED=true
# SUMMARIZATION_MODEL=anthropic/claude-haiku-4-5-20251001
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ jobs:
git tag -f "${{ needs.detect-version-bump.outputs.version }}"
git push --force origin "${{ needs.detect-version-bump.outputs.version }}"

- name: Update major version tag
run: |
VERSION="${{ needs.detect-version-bump.outputs.version }}"
MAJOR="${VERSION%%.*}"
git tag -f "v${MAJOR}"
git push --force origin "v${MAJOR}"

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

Expand Down
20 changes: 19 additions & 1 deletion .github/workflows/codespy-review.yml.example
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,22 @@ jobs:
# if: steps.codespy.outputs.issues-count > 10
# run: |
# echo "Too many issues found!"
# exit 1
# exit 1

# --- Using Memory (S3 persistence across runs) ---
# - name: Run CodeSpy Review
# uses: khezen/codespy@main
# with:
# model: 'anthropic/claude-opus-4-6'
# anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
# # AWS credentials for S3 memory backend
# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
# aws-region: 'us-east-1'
# # Enable memory globally
# memory-enabled: 'true'
# memory-backend: 's3'
# memory-s3-bucket: 'my-codespy-memory'
# # Use cheap model for reflection
# memory-distiller-model: 'anthropic/claude-haiku-4-5-20251001'
# memory-cartographer-model: 'anthropic/claude-haiku-4-5-20251001'
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ htmlcov/
.coverage
.coverage.*
.cache
.ruff_cache
nosetests.xml
coverage.xml
*.cover
Expand All @@ -54,6 +55,9 @@ coverage.xml

# Environments
.env
.env.bak*
.env.*.bak
.env.local
.venv
env/
venv/
Expand Down Expand Up @@ -88,4 +92,5 @@ dmypy.json
Thumbs.db

# Project specific
.cache/
.cache/
.kilo/
61 changes: 61 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Changelog

## [1.0.0] - 2026-08-18

### Added
- Cross-review memory system (Hippocampus) with S3/filesystem storage backends
- Context window overflow resilience (`ContextSafe` wrapper with automatic RLM fallback)
- Scope resolver: deterministic analysis + ReAct agent refinement (replaces `ScopeIdentifier`)
- Patch compaction: expands diff hunks to enclosing function boundaries via Tree-sitter
- Deterministic package manifest parser: extracts package identity from 25+ formats without LLM (npm, Go, pip, Cargo, Maven, Gradle, Composer, Bundler, NuGet, Swift, Pub, Hex, Helm, etc.)
- Tree-sitter extractors for Bash, C++, C#, PHP, Ruby
- Ripgrep fallback extractor for languages without Tree-sitter grammar
- Unified storage abstraction layer (`tools/storage/`) with filesystem and S3 backends
- Audit signature: dedicated module for review quality assessment and recommendation
- Reasoning effort configuration (`minimal|low|medium|high`) — maps to provider-native parameters (Anthropic thinking budget, OpenAI reasoning_effort)
- Per-signature `max_tokens` output token budget (replaces `max_reasoning_tokens`)
- TwoStepAdapter with dedicated extraction model for structured field extraction
- Memory storage access verification (S3/filesystem connectivity check at startup)
- Sparse checkout support in scope resolver for large monorepos
- Deno runtime in Docker image (required by DSPy RLM sandbox)
- Full documentation suite: architecture, configuration, development, memory, usage
- GitHub Action: reasoning effort, summary, and temperature inputs

### Security
- S3 path traversal hardening: `_resolve_path` decodes percent-encoded input before validation (catches `%2e%2e`, `%2f..%2f` — CWE-22)
- `json-repair` pinned to >=0.56.0 (GHSA-xf7x-x43h-rpqh)
- `litellm` floor raised to ^1.84.0 (excludes known-vulnerable versions)
- `gitpython` floor raised to >=3.1.41 (excludes CVE-affected versions)
- `markdownify` floor raised to >=0.14.0 (excludes known-vulnerable versions)

### Changed
- **BREAKING**: `MergeRequest` model renamed to `PullRequest` (backward-compat alias removed)
- **BREAKING**: `ReviewContext.merge_request` field → `pull_request` (compat property removed)
- **BREAKING**: CLI argument `mr_url` → `pr_url`; `fetch_merge_request()` → `fetch_pull_request()`
- **BREAKING**: `build_mr_from_diff()` → `build_pr_from_diff()`
- **BREAKING**: `ReviewResult` fields: `mr_number`→`pr_number`, `mr_title`→`pr_title`, `mr_url`→`pr_url`
- **BREAKING**: MCP tool `review_pr` parameter renamed: `mr_url` → `pr_url`
- **BREAKING**: `tools/filesystem` module moved to `tools/storage/filesystem` (import path changed)
- **BREAKING**: Per-signature `max_context_size` and `max_reasoning_tokens` env vars replaced by `reasoning_effort`, `temperature`, and `max_tokens`
- **BREAKING**: GitHub Action inputs removed: `*-max-context-size`, `*-max-reasoning-tokens` (replaced by `*-reasoning-effort`)
- Docker base image: Alpine → Debian slim (glibc required by Deno)
- `dspy` dependency: ^3.1.3 → ^3.3.0
- `mcp` dependency: >=1.0.0 → >=1.29.0,<2.0.0
- `litellm` dependency: ^1.81.6 → ^1.84.0
- `gitpython` dependency: >=3.1.0 → >=3.1.41
- `json-repair` dependency: ^0.55.1 → >=0.56.0
- `markdownify` dependency: >=0.13.0 → >=0.14.0
- ScopeIdentifierSignature → ScopeRefinementSignature (extracted to `ScopeResolver` module)
- MRSummarySignature → PRSummarySignature (extracted to `Summarizer` module with config key `summary`)
- `ReviewMetadata` model introduced to reduce parameter proliferation
- Per-module overflow detection replaced by centralized `ContextSafe` wrapper
- README rewritten: detailed sections moved to `docs/`, simplified TOC
- `codespy.yaml` expanded with memory, reasoning, and per-signature configuration (194 → 326 lines)

### Removed
- `ScopeIdentifier` module (replaced by `ScopeResolver`)
- `tools/filesystem/__init__.py` (replaced by `tools/storage/` abstraction)
- `default_max_context_size` and `default_max_reasoning_tokens` settings
- Per-signature `MAX_CONTEXT_SIZE` and `MAX_REASONING_TOKENS` env vars (replaced by `REASONING_EFFORT` and `MAX_TOKENS`)
- `MergeRequest` backward-compat alias
- Per-module `_would_overflow_context()` methods
33 changes: 19 additions & 14 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# syntax=docker/dockerfile:1

# Build stage with Poetry
FROM python:3.11-alpine AS builder
# Build stage
FROM python:3.11-slim AS builder

WORKDIR /app

# Install build dependencies for Python packages with native extensions
RUN apk add --no-cache \
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
gcc \
musl-dev \
libffi-dev \
&& pip install --no-cache-dir poetry
&& pip install --no-cache-dir poetry \
&& rm -rf /var/lib/apt/lists/*

# Copy project files
COPY pyproject.toml poetry.lock* README.md ./
Expand All @@ -23,15 +23,19 @@ RUN poetry config virtualenvs.create false \
&& poetry install --only main --no-interaction --no-ansi

# Runtime stage
FROM python:3.11-alpine
FROM python:3.11-slim

WORKDIR /app

# Install runtime dependencies
RUN apk add --no-cache \
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
ripgrep \
&& adduser -D -u 1000 codespy
&& rm -rf /var/lib/apt/lists/* \
&& useradd -m -u 1000 codespy

# Copy Deno binary (glibc works natively on Debian)
COPY --from=denoland/deno:bin-2.9.5 /deno /usr/local/bin/deno

# Copy installed packages from builder
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
Expand All @@ -43,19 +47,20 @@ COPY src/ ./src/
# Copy config to user's home directory
COPY codespy.yaml /home/codespy/codespy.yaml

# Set up cache directory and DSPy local_cache directory
RUN mkdir -p /home/codespy/.cache/codespy && \
chown -R codespy:codespy /home/codespy/.cache /home/codespy/codespy.yaml
# Pre-cache Deno/Pyodide dependencies and set up directories
ENV DENO_DIR=/home/codespy/.cache/deno
RUN mkdir -p /home/codespy/.cache/codespy \
&& (deno cache /usr/local/lib/python3.11/site-packages/dspy/primitives/runner.js || true) \
&& chown -R codespy:codespy /home/codespy/.cache /home/codespy/codespy.yaml

# Switch to non-root user
USER codespy

# Change to writable directory for DSPy's local_cache
WORKDIR /home/codespy

# Set environment variables
ENV PYTHONUNBUFFERED=1
ENV HOME=/home/codespy
ENV DENO_DIR=/home/codespy/.cache/deno

ENTRYPOINT ["codespy"]
CMD ["--help"]
Loading
Loading