Skip to content
Draft
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
59 changes: 54 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,68 @@ on:
pull_request:
branches: [main]

permissions:
contents: read

jobs:
smoke:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true

- name: Install dev dependencies
run: uv sync --extra dev

- name: ruff check
run: uv run ruff check src/reflect tests

- name: ruff format check
run: uv run ruff format --check src/reflect tests

- name: mypy
run: uv run mypy src/reflect

test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12"]
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
- name: Set up uv
uses: astral-sh/setup-uv@v3
with:
python-version: ${{ matrix.python-version }}
enable-cache: true

- name: Configure Python ${{ matrix.python-version }}
run: uv python pin ${{ matrix.python-version }}

- name: Install dev dependencies
run: uv sync --extra dev

- name: Run pytest
run: uv run pytest --cov=reflect --cov-report=term-missing

smoke:
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true

- name: Install package
run: uv sync --all-extras

- name: Smoke test
run: bash scripts/smoke.sh
48 changes: 48 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Docs

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: docs-${{ github.ref }}
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up uv
uses: astral-sh/setup-uv@v3
with:
enable-cache: true

- name: Install docs dependencies
run: uv sync --extra docs

- name: Build site
run: uv run mkdocs build --strict

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: site

deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
17 changes: 6 additions & 11 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,14 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Build tarball
run: |
VERSION="${GITHUB_REF#refs/tags/}"
mkdir -p dist/reflect-cli
cp reflect dist/reflect-cli/
cp -r lib dist/reflect-cli/
cp -r skill dist/reflect-cli/
cp -r hooks dist/reflect-cli/
cp -r templates dist/reflect-cli/
tar -czf "dist/reflect-cli-${VERSION}.tar.gz" -C dist reflect-cli
- name: Set up uv
uses: astral-sh/setup-uv@v3

- name: Build wheel and sdist
run: uv build

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/reflect-cli-*.tar.gz
files: dist/*
generate_release_notes: true
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ __pycache__/
*.pyc
bench/results/tmp-*

# Python build / dev artifacts
build/
dist/
*.egg-info/
.venv/
.mypy_cache/
.pytest_cache/
.ruff_cache/
.coverage
htmlcov/

# mkdocs build output
site/

# Tool-managed artifacts (installed by `reflect init` via their own tools)
.agents/
.claude/skills/qmd
Expand Down
49 changes: 29 additions & 20 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,42 @@ Persistent, compounding knowledge base for any repository. Reads raw evidence fr

## Structure

- `reflect` — CLI entry point (Python)
- `lib/` — CLI modules (evidence, context, init, search, status, sessions, timeline, improve, metrics, ingest, lint, wiki)
- `lib/evidence.py` — fixed evidence gathering pipeline (Entire CLI + git)
- `lib/wiki.py` — wiki layer utilities (frontmatter, page I/O, index scanning, index.md)
- `lib/ingest.py` — two-step wiki ingest (triage → write) + qmd re-indexing
- `lib/lint.py` — wiki health checks (stale, orphan, duplicate, coverage, resolved)
- `skill/SKILL.md` — skill source (dev copy; install copies to `.claude/skills/reflect/`)
- `pyproject.toml` — package metadata, console script entry point (`reflect = reflect.cli:main`)
- `src/reflect/` — Python package (installed as `reflect-cli`)
- `cli.py` — argparse dispatch, entry point
- `__main__.py` — enables `python -m reflect`
- `_version.py` — single source of truth for `__version__`
- `evidence.py` — fixed evidence gathering pipeline (Entire CLI + git)
- `wiki.py` — wiki layer utilities (frontmatter, page I/O, index scanning, index.md)
- `ingest.py` — two-step wiki ingest (triage → write) + qmd re-indexing
- `lint.py` — wiki health checks (stale, orphan, duplicate, coverage, resolved)
- `context.py`, `init.py`, `search.py`, `status.py`, `sessions.py`, `timeline.py`, `improve.py`, `metrics.py` — subcommand implementations
- `sources.py`, `fmt.py`, `aggregates.py` — shared helpers
- `_data/` — package runtime data (copied into target repos on `reflect init`)
- `_data/templates/` — `format.yaml` and `config.yaml` templates
- `_data/skill/SKILL.md` — Claude Code skill source
- `_data/skill/agents/keeper.md` — keeper subagent definition
- `_data/hooks/session-start.sh` — SessionStart hook for knowledge base freshness
- `SPEC.md` — specification for `.reflect/` directory format
- `hooks/session-start.sh` — SessionStart hook for knowledge base freshness
- `install.sh` — installer (symlinks CLI to `~/.local/bin`)
- `README.md` — user-facing docs
- `ROADMAP.md` — future phases
- `CLAUDE.md` — this file

## Development

- Edit `lib/evidence.py` to change evidence gathering
- Edit `lib/context.py` to change synthesis pipeline, system prompt, or validation
- Edit `lib/wiki.py` to change wiki utilities (frontmatter, page format, index.md)
- Edit `lib/ingest.py` to change knowledge extraction (triage/write subagent prompts)
- Edit `lib/lint.py` to change wiki health checks
- Edit `lib/` to change CLI commands
- Edit `.reflect/format.yaml` (in any repo) to customize seed categories
- Edit `skill/SKILL.md` to change the Claude Code skill (source of truth)
- Test locally: `python3 reflect status` or `python3 reflect search <query>`
- Test wiki: `python3 reflect init && python3 reflect ingest --verbose && python3 reflect lint`
- Install CLI via `./install.sh`; the skill is project-local under `.claude/skills/reflect/`
- Install for development: `uv sync --all-extras` (creates editable install + dev + docs deps)
- Run the CLI: `uv run reflect <subcommand>` or activate the venv and use `reflect` directly
- Edit `src/reflect/evidence.py` to change evidence gathering
- Edit `src/reflect/context.py` to change synthesis pipeline, system prompt, or validation
- Edit `src/reflect/wiki.py` to change wiki utilities (frontmatter, page format, index.md)
- Edit `src/reflect/ingest.py` to change knowledge extraction (triage/write subagent prompts)
- Edit `src/reflect/lint.py` to change wiki health checks
- Edit `src/reflect/cli.py` to change CLI surface (flags, subcommand wiring)
- Edit `src/reflect/_data/templates/format.yaml` to change the default user-facing schema
- Edit `src/reflect/_data/skill/SKILL.md` to change the Claude Code skill (source of truth)
- Test locally: `uv run reflect status`
- Test wiki: `uv run reflect init && uv run reflect ingest --verbose && uv run reflect lint`
- Smoke test: `bash scripts/smoke.sh`

## Session Insights

Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,22 @@

## Quick Start

Install the CLI with [uv](https://docs.astral.sh/uv/) (recommended):

```bash
curl -fsSL https://raw.githubusercontent.com/codeyogi911/reflect/main/install.sh | bash
uv tool install reflect-cli
```

Or run ad-hoc without installing:

```bash
uvx reflect --help
```

Or via pip:

```bash
pip install reflect-cli
```

Then in any git repo:
Expand Down Expand Up @@ -250,7 +264,18 @@ Default max budget is $0.05 per context generation (Claude Haiku), though typica

## Contributing

PRs welcome. For development, symlink `reflect` to the repo script (or run `python3 reflect …` directly) so `lib/` edits take effect without reinstalling the release tarball.
PRs welcome. For development:

```bash
git clone https://github.com/codeyogi911/reflect
cd reflect
uv sync --all-extras # editable install + dev + docs deps
uv run reflect status # run the CLI
uv run pytest # run tests
uv run ruff check # lint
```

Edits under `src/reflect/` take effect immediately via the editable install.

## License

Expand Down
6 changes: 6 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Commands

The full CLI reference below is generated from `reflect --help` at build time
(see `docs/hooks/cli_reference.py`).

{{ cli_reference }}
82 changes: 82 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Configuration

reflect is configured at three layers, all project-scoped:

1. **`.reflect/format.yaml`** — what categories the wiki has and how strict the
triage subagent is.
2. **`.reflect/config.yaml`** — operational settings (e.g., `session_start: auto|manual`).
3. **Environment variables** — runtime knobs (model, budget, home).

There is **no global `~/.reflect/`**. Configuration travels with the repo.

## `.reflect/format.yaml`

The user-facing schema. Defines the wiki sections (categories), their recency
windows, and bullet limits. The triage subagent uses this as guidance but can
also propose new categories dynamically.

```yaml
sections:
- name: Key Decisions & Rationale
purpose: why things are the way they are, not what they are
max_bullets: 8
recency: 30d

- name: Gotchas & Friction
purpose: things that burned time or surprised the agent
max_bullets: 6
recency: 14d

- name: Open Work
purpose: unfinished items a new session should pick up
max_bullets: 5
recency: 7d

- name: Critical Pitfalls
purpose: agent mistakes, reverted work, and failed approaches
max_bullets: 8
recency: 90d
entry_fields:
- mistake # what the agent did wrong
- consequence # what broke or had to be reverted
- rule # the "don't do X because Y" directive

citations: required
max_lines: 150
```

Field reference:

- `sections[].name` — display name (also drives the wiki subdirectory slug).
- `sections[].purpose` — guidance the LLM uses when deciding what fits.
- `sections[].max_bullets` — soft cap on entries per section in the briefing.
- `sections[].recency` — duration string (e.g. `30d`); pages older than this in
this section are flagged stale by `reflect lint`.
- `sections[].entry_fields` — optional structured-bullet schema (e.g. for pitfalls).
- `citations` — `required` forces every bullet to cite a checkpoint/commit/file.
- `max_lines` — cap on the synthesized `context.md`.

## `.reflect/config.yaml`

Operational knobs:

```yaml
session_start: auto # auto = SessionStart hook prints REFLECT_WIKI_INGEST
# manual = hook only prints a hint
```

## Environment variables

| Variable | Purpose | Default |
|---------------------------|--------------------------------------------------|---------------------------------|
| `REFLECT_MODEL` | Claude model for triage/write/context subagents | `claude-haiku-4-5-20251001` |
| `REFLECT_INGEST_BUDGET` | USD ceiling per `reflect ingest` invocation | `0.10` |
| `REFLECT_CONTEXT_BUDGET` | USD ceiling per `reflect context` invocation | `0.05` |
| `REFLECT_HOME` | Override the reflect data directory | unset |
| `QMD_LLAMA_GPU` | Set to `false` on headless boxes (qmd CPU only) | unset |

## Gitignore

`reflect init` will print a tip suggesting you add `.reflect/.last_run` to your
`.gitignore`. The rest of `.reflect/` (format, config, wiki pages, log.md,
index.md) is intended to be committed.
Loading
Loading