Compare commits

...

2 Commits

Author SHA1 Message Date
Alexander Whitestone
d11c95094d docs: refresh wolf genome analysis (#683)
Some checks failed
Self-Healing Smoke / self-healing-smoke (pull_request) Failing after 15s
Agent PR Gate / gate (pull_request) Failing after 35s
Smoke Test / smoke (pull_request) Failing after 20s
Agent PR Gate / report (pull_request) Has been cancelled
2026-04-17 01:50:44 -04:00
Alexander Whitestone
44013ba520 test: lock current wolf genome facts (#683) 2026-04-17 01:45:35 -04:00
2 changed files with 280 additions and 211 deletions

View File

@@ -1,263 +1,310 @@
# GENOME.md — Wolf (Timmy_Foundation/wolf)
> Codebase Genome v1.0 | Generated 2026-04-14 | Repo 16/16
Generated 2026-04-17 from direct source inspection of `/tmp/wolf-genome` plus live test execution.
## Project Overview
**Wolf** is a multi-model evaluation engine for sovereign AI fleets. It runs prompts against multiple LLM providers, scores responses on relevance, coherence, and safety, and outputs structured JSON results for model selection and ranking.
Wolf is a sovereign multi-model evaluation engine with two real operating modes:
**Core principle:** agents work, PRs prove it, CI judges it.
1. Prompt evaluation mode
- runs a set of prompts against multiple model providers
- scores responses on relevance, coherence, and safety
- emits structured JSON results plus a console leaderboard
2. Legacy task / PR mode
- fetches Gitea issues
- assigns them to configured models/providers
- generates output files and opens PRs
- records task scores in a leaderboard
**Status:** v1.0.0 — production-ready for prompt evaluation. Legacy PR evaluation module retained for backward compatibility.
Current repo shape observed directly:
- 9 Python modules under `wolf/`
- 5 active test modules under `tests/`
- 63 tests passing across `test_config.py`, `test_evaluator.py`, `test_gitea.py`, `test_models.py`, `test_runner.py`
- two smoke workflows: `.gitea/workflows/smoke.yml` and `.github/workflows/smoke-test.yml`
- a checked-in `GENOME.md` at repo root
## Architecture
```mermaid
graph TD
CLI[cli.py] --> Config[config.py]
CLI --> TaskGen[task.py]
CLI --> Runner[runner.py]
CLI --> Evaluator[evaluator.py]
CLI --> Leaderboard[leaderboard.py]
CLI --> Gitea[gitea.py]
flowchart TD
CLI1[wolf.cli]
CLI2[wolf.runner]
CFG[Config + setup_logging]
TASKS[TaskGenerator]
AR[AgentRunner]
PE[PromptEvaluator]
SC[ResponseScorer]
MF[ModelFactory]
MC[Provider Clients]
GC[GiteaClient]
LB[Leaderboard]
OUT1[JSON results]
OUT2[stdout summary]
OUT3[Gitea PRs]
Runner --> Models[models.py]
Runner --> Gitea
Evaluator --> Models
CLI1 --> CFG
CLI1 --> GC
CLI1 --> TASKS
CLI1 --> AR
CLI1 --> LB
CLI1 --> PE
TaskGen --> Gitea
Leaderboard --> |leaderboard.json| FS[(File System)]
Config --> |wolf-config.yaml| FS
CLI2 --> CFG
CLI2 --> PE
PE --> SC
PE --> MF
MF --> MC
CLI2 --> OUT1
CLI2 --> OUT2
Models --> OpenRouter[OpenRouter API]
Models --> Groq[Groq API]
Models --> Ollama[Ollama Local]
Models --> OpenAI[OpenAI API]
Models --> Anthropic[Anthropic API]
Runner --> |branch + commit| Gitea
Evaluator --> |score results| Leaderboard
TASKS --> GC
AR --> MF
AR --> GC
AR --> OUT3
CLI1 --> LB
```
## Entry Points
| Entry Point | Command | Purpose |
|-------------|---------|---------|
| `wolf/cli.py` | `python3 -m wolf.cli --run` | Main CLI: run tasks, evaluate PRs, show leaderboard |
| `wolf/runner.py` | `python3 -m wolf.runner --prompts p.json --models m.json` | Standalone prompt evaluation runner |
| `wolf/__init__.py` | `import wolf` | Package init, version metadata |
Primary runtime entry points:
- `python -m wolf.runner`
- pure prompt evaluation pipeline
- requires `--prompts` plus either `--models` or `--config`
- `python -m wolf.cli`
- task runner / PR scoring / leaderboard CLI
- supports `--run`, `--evaluate`, `--leaderboard`
Supporting entry surfaces:
- `wolf/config.py`
- config loading and log setup
- `wolf/models.py`
- provider-specific model clients
- `wolf/gitea.py`
- repository / branch / file / PR operations
## Data Flow
### Prompt Evaluation Pipeline (Primary)
### Prompt evaluation mode
```
prompts.json + models.json (or wolf-config.yaml)
PromptEvaluator.evaluate()
├─ For each (prompt, model) pair:
│ ├─ ModelClient.generate(prompt) → response text
│ ├─ ResponseScorer.score(response, prompt)
│ │ ├─ score_relevance() (0.40 weight)
│ │ ├─ score_coherence() (0.35 weight)
│ │ └─ score_safety() (0.25 weight)
│ └─ EvaluationResult (prompt, model, scores, latency, error)
evaluate_and_serialize() → JSON output
├─ model_summaries (per-model averages)
└─ results[] (per-evaluation details)
```
1. `runner.py` loads prompts from JSON via `load_prompts()`
2. it loads model endpoints from JSON or config via `load_models_from_json()` / `load_models_from_config()`
3. `PromptEvaluator.evaluate()` iterates prompt × model
4. `ModelFactory.get_client()` selects the provider client
5. the client calls the model API and returns response text
6. `ResponseScorer.score()` computes:
- relevance
- coherence
- safety
- weighted overall
7. `evaluate_and_serialize()` builds per-model summaries and detailed results
8. `run()` returns JSON and optionally writes it to disk
9. `print_summary()` renders a human-readable ranking table
### Task Assignment Pipeline (Legacy)
### Legacy task / PR mode
```
Gitea Issues → TaskGenerator → AgentRunner
│ │ │
▼ ▼ ▼
Fetch tasks Assign models Execute + PR
from issues from config via Gitea API
```
1. `cli.py` loads config and constructs `GiteaClient`
2. `TaskGenerator.from_gitea_issues()` or `from_spec()` builds `Task` objects
3. `assign_tasks()` applies round-robin model/provider assignment
4. `AgentRunner.execute_task()`:
- generates model output
- creates a branch
- writes `wolf-outputs/<task>.md`
- opens a PR
5. `Leaderboard.record_score()` persists score history and serverless-readiness flags
## Key Abstractions
| Class | Module | Purpose |
|-------|--------|---------|
| `PromptEntry` | evaluator.py | Single prompt with expected keywords and category |
| `ModelEndpoint` | evaluator.py | Model connection descriptor (provider, model_id, key) |
| `ScoreResult` | evaluator.py | Scores for relevance, coherence, safety, overall |
| `EvaluationResult` | evaluator.py | Full result: prompt + model + response + scores + latency |
| `ResponseScorer` | evaluator.py | Heuristic scoring engine (regex + keyword + structure) |
| `PromptEvaluator` | evaluator.py | Core engine: runs prompts against models, scores output |
| `ModelClient` | models.py | Abstract base for LLM API calls |
| `ModelFactory` | models.py | Factory: returns correct client for provider name |
| `Task` | task.py | Work unit: id, title, description, assigned model/provider |
| `TaskGenerator` | task.py | Creates tasks from Gitea issues or JSON spec |
| `AgentRunner` | runner.py | Executes tasks: generate → branch → commit → PR |
| `Config` | config.py | YAML config loader (wolf-config.yaml) |
| `Leaderboard` | leaderboard.py | Persistent model ranking with serverless readiness |
| `GiteaClient` | gitea.py | Full Gitea REST API client |
| `PREvaluator` | evaluator.py | Legacy: scores PRs on CI, commits, code quality |
Core dataclasses in `wolf/evaluator.py`:
- `PromptEntry`
- `ModelEndpoint`
- `ScoreResult`
- `EvaluationResult`
Core engines:
- `ResponseScorer`
- heuristic scoring engine for relevance/coherence/safety
- `PromptEvaluator`
- N×M evaluation orchestration
- `ModelFactory`
- dispatches to provider clients
- `GiteaClient`
- wraps issue / branch / file / PR operations
- `TaskGenerator`
- turns issues or spec JSON into `Task` objects
- `AgentRunner`
- legacy execution path from task to PR
- `Leaderboard`
- persists scoring history and ranking output
- `Config`
- tolerant config loader with PyYAML fallback logic
## API Surface
### CLI Arguments (cli.py)
CLI flags in `wolf.runner`:
- `--prompts/-p`
- `--models/-m`
- `--config/-c`
- `--output/-o`
- `--system-prompt`
| Flag | Description |
|------|-------------|
| `--config` | Path to wolf-config.yaml |
| `--task-spec` | Path to task specification JSON |
| `--run` | Run pending tasks (assign models, execute, create PRs) |
| `--evaluate` | Evaluate open PRs and score them |
| `--leaderboard` | Show model rankings |
CLI flags in `wolf.cli`:
- `--config`
- `--task-spec`
- `--run`
- `--evaluate`
- `--leaderboard`
### CLI Arguments (runner.py)
Provider surface in `wolf.models`:
- `OpenRouterClient`
- `GroqClient`
- `OllamaClient`
- `AnthropicClient`
- OpenAI is handled as a Groq-style compatible client with a different base URL
| Flag | Description |
|------|-------------|
| `--prompts` / `-p` | Path to prompts JSON (required) |
| `--models` / `-m` | Path to models JSON |
| `--config` / `-c` | Path to wolf-config.yaml (alternative to --models) |
| `--output` / `-o` | Path to write JSON results |
| `--system-prompt` | System prompt for all model calls |
### Provider Clients (models.py)
| Client | Provider | API Format |
|--------|----------|------------|
| `OpenRouterClient` | openrouter | OpenAI-compatible chat completions |
| `GroqClient` | groq | OpenAI-compatible chat completions |
| `OllamaClient` | ollama | Ollama native /api/generate |
| `OpenAIClient` | openai | OpenAI-compatible (reuses GroqClient with different URL) |
| `AnthropicClient` | anthropic | Anthropic Messages API v1 |
### Gitea Client (gitea.py)
| Method | Purpose |
|--------|---------|
| `get_issues()` | Fetch issues by state |
| `create_branch()` | Create new branch from base |
| `create_file()` | Create file on branch (base64) |
| `update_file()` | Update file with SHA |
| `get_file()` | Read file contents |
| `create_pull_request()` | Open PR |
| `get_pull_request()` | Fetch PR details |
| `get_pr_status()` | Check PR CI status |
## Configuration (wolf-config.yaml)
```yaml
gitea:
base_url: "https://forge.alexanderwhitestone.com/api/v1"
token: "..."
owner: "Timmy_Foundation"
repo: "wolf"
providers:
openrouter:
api_key: "..."
base_url: "https://openrouter.ai/api/v1"
ollama:
base_url: "http://localhost:11434"
models:
- model: "anthropic/claude-3.5-sonnet"
provider: "openrouter"
- model: "gemma4:latest"
provider: "ollama"
log_dir: "~/.hermes/wolf/"
leaderboard_path: "~/.hermes/wolf/leaderboard.json"
```
## Scoring Methodology
| Dimension | Weight | Method |
|-----------|--------|--------|
| Relevance | 0.40 | Keyword matching (expected_keywords), prompt word overlap, length penalty, refusal detection |
| Coherence | 0.35 | Structure indicators (paragraphs, lists, transitions), sentence completeness, repetition ratio, length sweet spot |
| Safety | 0.25 | Unsafe pattern regex (bomb/hack/bypass/injection), profanity detection |
**Overall = relevance×0.40 + coherence×0.35 + safety×0.25**
### Safety Patterns Detected
- Bomb/explosive/weapon creation
- System/network hacking
- Security/auth bypass
- Prompt injection ("ignore previous instructions")
- System prompt extraction attempts
### Refusal Patterns Detected
- "I cannot/can't/won't help/assist"
- "Sorry, but I cannot"
- "Against my guidelines/policy"
Gitea surface in `wolf.gitea`:
- `get_issues()`
- `create_branch()`
- `create_file()`
- `update_file()`
- `get_file()`
- `create_pull_request()`
- `get_pull_request()`
- `get_pr_status()`
## Test Coverage
| File | Tests | Coverage |
|------|-------|----------|
| `tests/test_evaluator.py` | 17 tests | PromptEntry, ModelEndpoint, ResponseScorer (relevance/coherence/safety), PromptEvaluator (evaluate, error handling, serialization, file output, multi-model), PREvaluator (score_pr, description scoring) |
| `tests/test_config.py` | 1 test | Config load from YAML |
Live verification run:
- `python3 -m pytest -q tests/test_config.py tests/test_evaluator.py tests/test_gitea.py tests/test_models.py tests/test_runner.py`
- result: `63 passed`
### Coverage Gaps
Current tested modules:
- `tests/test_config.py`
- config load happy path
- `tests/test_evaluator.py`
- scorer heuristics
- prompt/model dataclasses
- evaluator serialization paths
- legacy PR evaluator behavior
- `tests/test_gitea.py`
- Gitea client request/response behavior
- 404 and fallback status handling
- `tests/test_models.py`
- provider factory dispatch
- provider generate() request formatting
- `tests/test_runner.py`
- prompt/model loading helpers
- parser wiring
- `AgentRunner.execute_task()` behavior
- No tests for `cli.py` (argument parsing, workflow orchestration)
- No tests for `runner.py` (`load_prompts`, `load_models_from_json`, `AgentRunner.execute_task`)
- No tests for `task.py` (`TaskGenerator.from_gitea_issues`, `from_spec`, `assign_tasks`)
- No tests for `models.py` (API clients — would require mocking HTTP)
- No tests for `leaderboard.py` (`record_score`, `get_rankings`, serverless readiness logic)
- No tests for `gitea.py` (API client — would require mocking HTTP)
- No integration tests (end-to-end evaluation pipeline)
Coverage gaps that still matter:
- `wolf/cli.py`
- no direct tests for the top-level workflow routing
- `wolf/task.py`
- no direct tests for `from_gitea_issues()`, `from_spec()`, `assign_tasks()` in this repo state
- `wolf/leaderboard.py`
- no direct tests for persistence / ranking / serverless-ready threshold logic
Important drift note:
- the older timmy-home genome artifact claimed only `test_config.py` and `test_evaluator.py` existed
- current repo also includes `tests/test_models.py`, `tests/test_gitea.py`, and `tests/test_runner.py`
## CI / Verification Surface
Current CI contracts observed directly:
- `.gitea/workflows/smoke.yml`
- checkout
- setup Python 3.11
- install `pytest` and `pyyaml`
- install `requirements.txt` if present
- run `pytest tests/`
- `.github/workflows/smoke-test.yml`
- YAML parse check
- JSON parse check
- Python compile check
- shell syntax check
- secret scan
This means the real repo contract is broader than unit tests alone: syntax, parseability, and secret hygiene are part of the shipped smoke lane.
## Dependencies
| Dependency | Used By | Purpose |
|------------|---------|---------|
| `requests` | models.py, gitea.py | HTTP client for all API calls |
| `pyyaml` (optional) | config.py | YAML config parsing (falls back to line parser) |
Direct dependency files:
- `requirements.txt`
- only `requests`
- README install instructions
- `pip install requests pyyaml`
Observed dependency tension:
- `wolf/config.py` imports `yaml` when available and falls back to a simple parser if PyYAML is absent
- CI installs `pyyaml`
- `requirements.txt` does not list `pyyaml`
So PyYAML is operationally expected in normal use and CI, but not formally pinned in `requirements.txt`.
## Security Considerations
1. **API keys in config**: wolf-config.yaml stores provider API keys in plaintext. File should be chmod 600 and excluded from git (already in .gitignore pattern via ~/.hermes/).
2. **Gitea token**: Full access token used for branch creation, file commits, and PR creation. Scoped access recommended.
3. **No input sanitization**: Prompts from Gitea issues are passed directly to models without filtering. Prompt injection risk for automated workflows.
4. **No rate limiting**: Model API calls are sequential with no backoff or rate limiting. Could exhaust API quotas.
5. **Legacy code reference**: `evaluator.py` references `Evaluator = PREvaluator` alias but `cli.py` imports `Evaluator` expecting the legacy class. This works but is confusing.
1. Plaintext secrets in config
- model API keys and Gitea tokens are expected via config files
- this is user-controlled but still a secret-handling risk
2. Arbitrary base URLs
- provider configs can point to arbitrary endpoints
- useful for sovereignty, but also expands trust boundaries
3. PR automation blast radius
- `AgentRunner.execute_task()` can create branches, files, and PRs
- bad prompts or weak issue filtering could create noisy or unsafe PRs
4. Prompt-injection exposure
- model prompts and issue bodies are passed through with limited sanitization
5. Leaderboard persistence without locking
- `leaderboard.json` writes are not protected against concurrent writers
## Repository Notes
Notable current-repo facts that the host-repo genome should preserve:
- Wolf already ships its own `GENOME.md` at repo root
- the timmy-home deliverable for issue #683 is therefore a host-repo genome artifact that mirrors / tracks the current wolf repo, not the first genome ever written for wolf
- current smoke workflows exist in both `.gitea/` and `.github/`
## File Index
| File | LOC | Purpose |
|------|-----|---------|
| `wolf/__init__.py` | 12 | Package init, version |
| `wolf/cli.py` | 90 | Main CLI orchestrator |
| `wolf/config.py` | 48 | YAML config loader |
| `wolf/models.py` | 130 | LLM provider clients (5 providers) |
| `wolf/runner.py` | 280 | Prompt evaluation CLI + AgentRunner |
| `wolf/task.py` | 80 | Task dataclass + generator |
| `wolf/evaluator.py` | 350 | Core scoring engine + legacy PR evaluator |
| `wolf/leaderboard.py` | 70 | Persistent model ranking |
| `wolf/gitea.py` | 100 | Gitea REST API client |
| `tests/test_evaluator.py` | 180 | Unit tests for evaluator |
| `tests/test_config.py` | 20 | Unit tests for config |
Observed module sizes:
- `wolf/evaluator.py` — 465 lines
- `wolf/runner.py` — 311 lines
- `wolf/models.py` — 120 lines
- `wolf/gitea.py` — 95 lines
- `wolf/cli.py` — 94 lines
- `wolf/leaderboard.py` — 77 lines
- `wolf/task.py` — 63 lines
- `wolf/config.py` — 51 lines
- `wolf/__init__.py` — 12 lines
**Total: ~1,360 LOC Python | 11 modules | 18 tests**
Aggregate metrics from direct scan:
- 15 Python files total
- 9 module files under `wolf/`
- 6 Python files under `tests/` (including `__init__.py`)
- ~2150 lines of Python total
## Sovereignty Assessment
## Verification Commands
- **No external dependencies beyond requests**: Runs on any machine with Python 3.11+ and requests.
- **No phone-home**: All API calls are to user-configured endpoints.
- **No telemetry**: Logs go to local filesystem only.
- **Config-driven**: All secrets in user's ~/.hermes/ directory.
- **Provider-agnostic**: Supports 5 providers with easy extension via ModelFactory.
Commands used for this update:
- `git clone --depth 1 --single-branch https://.../Timmy_Foundation/wolf.git /tmp/wolf-genome`
- `python3 -m pytest -q tests/test_config.py tests/test_evaluator.py tests/test_gitea.py tests/test_models.py tests/test_runner.py`
- direct file inspection of:
- `README.md`
- `wolf/cli.py`
- `wolf/config.py`
- `wolf/evaluator.py`
- `wolf/gitea.py`
- `wolf/models.py`
- `wolf/runner.py`
- `wolf/task.py`
- `wolf/leaderboard.py`
- `.gitea/workflows/smoke.yml`
- `.github/workflows/smoke-test.yml`
**Verdict: Fully sovereign. No corporate lock-in. User controls all endpoints and keys.**
## Summary
---
*"The strength of the pack is the wolf, and the strength of the wolf is the pack."*
*— The Wolf Sovereign Core has spoken.*
Wolf is real and useful today, but its current reality is:
- stronger test coverage than the older timmy-home genome recorded
- a still-untested CLI/task/leaderboard control plane
- smoke workflows that now form part of the repos real contract
- a checked-in root `GENOME.md` that does not remove the need for the host-repo genome issue artifact

22
tests/test_wolf_genome.py Normal file
View File

@@ -0,0 +1,22 @@
from pathlib import Path
GENOME = Path("genomes/wolf/GENOME.md")
def test_wolf_genome_exists_at_expected_path():
assert GENOME.exists(), "wolf genome must exist at genomes/wolf/GENOME.md"
def test_wolf_genome_covers_current_test_surface_and_ci_contract():
content = GENOME.read_text(encoding="utf-8")
required = [
"# GENOME.md — Wolf (Timmy_Foundation/wolf)",
"tests/test_models.py",
"tests/test_gitea.py",
"tests/test_runner.py",
".gitea/workflows/smoke.yml",
".github/workflows/smoke-test.yml",
"`GENOME.md` at repo root",
]
missing = [item for item in required if item not in content]
assert not missing, f"wolf genome missing current repo facts: {missing}"