# Changelog All notable changes to RepoLens will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Fixed - Keep remote branch-review drafts separate from verified issue counts, enforce creation limits in the filing governor (including uncertain attempts and reopen suggestions), and reconcile counts and deferred work on resume. - Resolve remote branch-review refs and revision expressions through local aliases in the temporary clone, retaining both resolved commits before checkout so `HEAD`-relative refs keep their original meaning. Qualified branch refs, tags, and commit SHAs use Git's normal resolution rules. - Resume branch reviews of remote URLs at the saved commit before applying read-only isolation, including when refs are omitted or the remote branch has advanced. Preserve explicit ref checks, the original delta, and the saved task-hour cap. - Keep process-scope supervisors alive when an RPC client disconnects or cannot receive its reply, preserving worker cleanup and parent-death monitoring; completed scope destruction still shuts down cleanly without a delivered reply. - Clear inherited parent EXIT cleanup before parallel worker enrollment, so default heartbeat trap restoration cannot delete a shared remote clone while sibling lenses are still running. Callback cleanup and parent-owned scope collection remain active. - Restore log-lens test fixtures to the required existing-run resume contract, retain core utilities in the CI-like agent-free PATH on NixOS, and run CI on harness integration branches before publication (#405). - Branch reviews of remote project URLs clone full history and all branches, then check out an explicit review head before analysis, so merge-base resolution works (#400). - OpenCode invocations use `--auto` so non-interactive lenses can write findings to output directories outside the audited repository; explicit permission denials remain enforced (#409). - Parallel workers now use verified Linux cgroup v2 scopes with gated self-enrollment, retained kernel identities, pidfd TERM, shared-grace recursive KILL, and confirmed empty-scope cleanup. GNU timeout groups, new sessions, early wrapper exits, and inherited output writers remain contained; unsupported hosts fail before callbacks unless explicit sequential fallback was selected. Required Linux containment CI covers system Bash and Bash 4.0 ([#407](https://github.com/TheMorpheus407/RepoLens/issues/407), [#408](https://github.com/TheMorpheus407/RepoLens/issues/408)). - Synthesized filing now uses a deterministic governor: live citation verification, fresh duplicate checks, exact provider readbacks, atomic reservations, and permanent attempt markers replace the privileged filing agent. Invalid or stale success markers cannot bypass the gate; unsupported structured adapters fail before mutation ([#406](https://github.com/TheMorpheus407/RepoLens/issues/406)). - Branch-review findings are mechanically filtered against the pinned changed-file set before counting and synthesis and again before publication. Remote branch lenses produce drafts for governed filing; rejected proposals remain available with scope diagnostics ([#403](https://github.com/TheMorpheus407/RepoLens/issues/403)). - `branch-review --local` now preserves the regression finding contract—`[REGRESSION][SEVERITY]` titles, `Introduced By` / `Before / After`, exact complexity metadata, and validation evidence—instead of also presenting the generic `[SEVERITY]` audit-file contract; ordinary local audit output is unchanged ([#402](https://github.com/TheMorpheus407/RepoLens/issues/402)) - `branch-review` regression findings now use the same implementation-effort routing contract as audit findings: each issue selects exactly one 1-5 complexity tier, applies the matching `repolens/complexity/` label, and records `- **Complexity:** ()` in its body, while RepoLens pre-creates the five labels for branch-review runs ([#404](https://github.com/TheMorpheus407/RepoLens/issues/404)) - `branch-review` resume now fails fast when a non-empty run's persisted review head is not the checked-out commit, preventing its frozen delta from being paired with a different working tree. Check out the persisted head or start a new branch review; matching-head and empty-delta resumes are unchanged ([#398](https://github.com/TheMorpheus407/RepoLens/issues/398)) - `branch-review` resume now restores the persisted head ref in provenance output and rejects an explicitly supplied `--branch-head` whose ref spelling differs from the manifest, matching `--branch-base` drift handling. Omitting the flag restores the persisted spelling; repeating that spelling passes the ref check, while an alternate name for the same commit is rejected ([#399](https://github.com/TheMorpheus407/RepoLens/issues/399)) - `config/agent-pricing.json` refreshed to current Anthropic pricing (2026-05-24): corrected `claude-opus-4-6` from $15/$75 to $5/$25 per MTok, added `claude-sonnet-4-6` ($3/$15) and `claude-opus-4-7` ($5/$25), and updated the default model for `--agent claude` from `claude-sonnet-4-5` to `claude-sonnet-4-6`. Cost estimates shown by `--dry-run` and the confirmation prompt are now within ±10% of current published pricing ([#249](https://github.com/TheMorpheus407/RepoLens/issues/249)) - Parallel rate-limit aborts now preserve operator-visible terminal state: lens-level provider quota aborts finish as `status.json.state: "rate-limit-pending"` with CLI exit `3`, while SIGHUP, SIGINT, or SIGTERM during a rate-limit retry sleep finish as `interrupted` with the corresponding stopped reason and exit code `129`, `130`, or `143` ([#276](https://github.com/TheMorpheus407/RepoLens/issues/276)) - Greenfield planning now refreshes current backlog state before every planner iteration: forge runs read all currently open issues, `--local` runs read current draft markdown files, and planning stops instead of filing blind when forge backlog checks are unavailable ([#285](https://github.com/TheMorpheus407/RepoLens/issues/285)) ### Changed - `--resume` now accepts **no run id** and auto-selects the run to continue: it picks the most recent interrupted run under `logs/` (by directory mtime) and resumes it, logging `Auto-resuming latest interrupted run: `, so you no longer have to hunt for the id among near-empty rate-limited attempt dirs. Only genuine resume candidates qualify — completed/clean runs and retired (`supersede`d) runs are never auto-picked — and when none exists RepoLens stops with `No interrupted run found to resume; pass an explicit run id or start a fresh run.` (non-zero exit, no fresh run dir created). Explicit `--resume ` is unchanged, and `--resume --dry-run` now previews the auto-selected run instead of mis-parsing the flag as the run id ([#373](https://github.com/TheMorpheus407/RepoLens/issues/373)) - `clean` (and the `REPOLENS_AUTO_CLEAN` startup prune) now also protects a run from age-based pruning when its **most recent continuation attempt did not finish cleanly** — i.e. the run was rate-limited, interrupted, or failed on its last attempt — even when its `status.json`/`summary.json` would otherwise look clean. This stops a mid-continuation run from being silently pruned out from under an in-progress `--resume`, and such a run also becomes eligible for `--resume` with no run id (auto-select of the latest interrupted run). A run whose most recent attempt finished cleanly stays prunable by age as before, older runs that predate the continuation ledger are unaffected, and `--remove-incomplete` still overrides this to remove resume candidates ([#376](https://github.com/TheMorpheus407/RepoLens/issues/376)) - The default `--max-parallel` is now nproc-aware when the flag is unset: it resolves to `clamp(detected CPU cores, 8, 32)`, so small and CI hosts keep today's `8` while many-core machines scale up to `32` for a faster fan-out. An explicit `--max-parallel` is always authoritative and is never re-clamped — you can deliberately run below `8` or above `32` — and an invalid value (non-positive-integer) is now rejected at startup with a clear error instead of misbehaving deep in execution. Because a higher default trips provider rate limits sooner, pin the value down on small account tiers. The new `REPOLENS_NPROC` environment variable pins the detected core count (`clamp(REPOLENS_NPROC, 8, 32)`, parsed base-10) for deterministic runs, estimates, and tests; when unset, RepoLens detects cores via `nproc`/`getconf` and falls back to a floor of `8` ([#367](https://github.com/TheMorpheus407/RepoLens/issues/367)) - Polish mode now collects structured JSON suggestions, writes `logs//polish/ranked-suggestions.json`, and emits one `[POLISH]` lens-scoped polishing shortlist per lens with ranked top-N suggestions (default 3) and a voice-fit justification for each listed item. Forge runs create remote shortlist issues; `--local` runs write grouped markdown drafts under `logs//polish/filed/` ([#301](https://github.com/TheMorpheus407/RepoLens/issues/301), [#302](https://github.com/TheMorpheus407/RepoLens/issues/302)) ### Added - `--task-hours ` configures the target maximum human implementation effort per issue (default: 1 hour), including local output and synthesized findings; resumed runs retain the saved value (#397). - `--agent copilot`: native support for the GitHub Copilot CLI as an agent, invoked through `gh copilot` (the `gh` CLI auto-downloads the Copilot CLI on first run if it isn't already on `PATH`, so only `gh` itself plus an active Copilot subscription is required). RepoLens drives it non-interactively with `gh copilot -- -p "" --allow-all-tools --allow-all-paths --allow-all-urls --no-ask-user --no-color -s`, reusing the same DONE-streak, timeout, and cost-estimate machinery as every other agent. `copilot/` pins a specific model via `--model`, the new `REPOLENS_AGENT_TIMEOUT_COPILOT` environment variable sets a Copilot-specific per-invocation timeout with the usual precedence, `--dry-run` prices bare `copilot` as a Sonnet-class model (actual model varies by plan), and `copilot`/`copilot/` are also accepted as `--agent-override` targets. - `--mode branch-review`: a regression-only review pass over a branch. It takes `--branch-base ` (required; `--branch-head ` defaults to `HEAD` and must be the checked-out commit, since lenses read the working tree) and reviews exactly what the head introduced on top of the merge base it shares with the base ref. The delta uses **three-dot** semantics — `git diff `, equivalent to `base...head` — so commits that exist only on the base are never reported as branch changes, which a two-dot diff would surface as phantom "the branch deleted this" regressions. Lenses must clear a two-part discriminator before filing: the defect fails at the head *and* passed at the merge base, so pre-existing problems stay out of scope no matter how severe they look. Findings are filed with a `[REGRESSION]` title prefix and a `regression:/` label, keep `--min-severity` active, and see the full code-analysis lens fleet (the same set as `audit`). The full patch is persisted once to `logs//branch-diff.txt` and a bounded provenance manifest (base/head/merge-base SHAs, name-status, diffstat) to `logs//branch-manifest.md`; only the manifest is transported into prompts, as UNTRUSTED escaped data, so a multi-MB branch never inflates every lens prompt. An empty delta is a valid, successful no-op run that files nothing, and unresolvable refs, unrelated histories (no merge base, with a shallow-clone hint), and a non-checked-out `--branch-head` all fail fast with actionable messages ([#396](https://github.com/TheMorpheus407/RepoLens/issues/396)) - Native Cursor backends: `--agent cursor` runs unattended through Cursor CLI with subscription-backed Auto routing, while `cursor/` pins a plan model. `--agent cursor-ide` covers the distinct Cursor IDE/Composer use case through an explicit local filesystem handoff—random request ids, atomic hashed completion markers, invocation-private response snapshots, substantive lens-evidence validation, durable machine events, timeout detection, and normal RepoLens resume state—without requiring `cursor-agent`. Validation and downstream consumption use the same snapshotted bytes, and project citations cannot escape through symlinked path components. IDE handoffs require `--local` and run sequentially because Cursor exposes no supported unattended Composer API. All Cursor variants receive the subscription quota/cost view; the design is informed by the linked RepoLens Cursor Edition fork ([#390](https://github.com/TheMorpheus407/RepoLens/issues/390)) - `okf-compliance` content lens for focused audits of coherent documentation corpora against OKF v0.2. It distinguishes strict conformance defects from version migration and optional readiness improvements, and requires a concrete cataloging, reuse, provenance, navigation, or maintenance benefit before recommending adoption ([#387](https://github.com/TheMorpheus407/RepoLens/issues/387)) - Multi-file specifications for `greenfield` and `spec-change`: use `--spec-dir` with repeatable or comma-separated `--spec-glob` and `--spec-exclude` filters plus an optional `--spec-entry`. RepoLens defaults to recursive Markdown selection, resolves a deterministic entry-first/file-sorted bundle, preserves source paths for planning provenance and conflict reporting, shows the resolved set under `--dry-run`, and persists a manifest and combined snapshots under `logs//`. Bundle resume restores only frozen specification selection: authorization and output routing must be repeated through the current `--mode`, `--local`/`--forge`, optional `--output`, and `--yes` flags, which interruption hints now include. The existing `--spec ` workflow remains supported and is mutually exclusive with `--spec-dir` ([#389](https://github.com/TheMorpheus407/RepoLens/issues/389)) - Task-complexity estimation (1-5) and routing labels on findings: the audit model now estimates the **implementation effort to fix** each finding on a 1-5 scale (`1` Trivial, `2` Easy, `3` Medium, `4` High, `5` Critical/Complex) — orthogonal to severity, since a `critical` leaked secret may be a one-line fix (1) while a `low` cross-cutting refactor may be a major change (4). Audit findings (single-pass `audit` and multi-round `bugreport` synthesis) and `branch-review` regression findings carry a `repolens/complexity/<1-5>` label and a `- **Complexity:** ()` body line, and the finding registry gains an optional `complexity` field (integer 1-5 or `null`) in `findings.jsonl` plus a `complexity` column appended at the end of `findings.csv`. This lets downstream automation route each fix to a cost/capability model tier by label (e.g. `gh issue list --label repolens/complexity/1`) instead of guessing from the domain. The value is authored by the model, never computed by RepoLens; an absent or out-of-range estimate is stored as `null` (rejected, never clamped). No mode outside `audit`, `bugreport`, and `branch-review` emits a complexity estimate ([#385](https://github.com/TheMorpheus407/RepoLens/issues/385), [#404](https://github.com/TheMorpheus407/RepoLens/issues/404)) - `/` model pinning for the native agents: `claude/`, `codex/`, and `antigravity/` now select a specific model the same way `opencode/` always has, so you can run a cheap, fast model (e.g. `--agent claude/claude-haiku-4-5`) or target a newly released one without waiting for RepoLens to hardcode it. The model string is passed straight to the underlying CLI, the `/` forms are also valid `--agent-override` targets, and the `spark`/`sparc` presets keep no suffix (use `codex/` to choose a Codex model). Cost estimation no longer falls back to an arbitrary high default for an unknown model: a model RepoLens has exact pricing for is priced directly, and any other is approximated from keywords in its name — `flash`/`haiku`/`mini`/`8b`/`lite`/`nano` price as cheap, `opus`/`ultra`/`preview` as premium, everything else as standard ([#384](https://github.com/TheMorpheus407/RepoLens/issues/384)) - `--flat-rate` flag (with `REPOLENS_FLAT_RATE` env fallback): cost a run as a flat-rate subscription or free tier (Claude Pro, ChatGPT Plus, Gemini Advanced, Google AI Studio free tier, …) rather than pay-as-you-go tokens. Because the marginal per-token cost for these plans is `$0.00`, the confirmation prompt and `--dry-run` preview show `Estimated cost: ~$0.00` plus the expected number of LLM calls and how much of a typical 3-hour message cap or free-tier rate budget (e.g. Google AI Studio 15 RPM / 1500 RPD) the run will consume, so subscription users can pace or split a large audit instead of locking themselves out mid-run. It suppresses the per-token dollar estimate and the "2–5× higher" disclaimer; with a `$0.00` estimate the `--max-cost` guardrail never trips. Truthy env values (`true`/`1`/`yes`) enable it, and the CLI flag also enables it ([#384](https://github.com/TheMorpheus407/RepoLens/issues/384)) - `--agent antigravity`: native support for the official Google Antigravity CLI as a flagship agent alongside `claude`, `codex`, `spark`/`sparc`, and `opencode`. Install the `agy` binary with `curl -fsSL https://antigravity.google/cli/install.sh | bash` and authenticate via Google sign-in; RepoLens then drives it with the same DONE-streak, timeout, and cost-estimate machinery as every other agent. Its large context window (up to 1M tokens) suits auditing large codebases without splitting them across runs. The new `REPOLENS_AGENT_TIMEOUT_ANTIGRAVITY` environment variable sets an Antigravity-specific per-invocation timeout with the usual precedence (agent-specific > `REPOLENS_AGENT_TIMEOUT` > mode-specific > mode default), `--dry-run` prices it as Gemini 2.5 Pro, and `antigravity` is also accepted as an `--agent-override` target. This supersedes the earlier `--agent gemini` support ([#382](https://github.com/TheMorpheus407/RepoLens/issues/382)), which Google's deprecation of the standalone Gemini CLI for individual users made unusable; `--agent gemini` is no longer accepted ([#383](https://github.com/TheMorpheus407/RepoLens/issues/383)) - `--agent-override `: route specific domains or individual lenses to a different agent than the global `--agent`, so you can run a cheap model by default and spend a flagship model only where reasoning depth matters — the cost-vs-logic trade-off where a cheap model misses complex cross-file findings while a flagship model is wasteful on trivial domains. Takes comma-separated `key=agent` pairs, where `key` is a domain id or a fully-qualified `domain/lens` (a bare lens id is rejected as ambiguous, since one lens id can appear in multiple domains) and `agent` is any value `--agent` accepts. Precedence is `domain/lens` > `domain` > global `--agent`; the flag may be repeated and its pairs accumulate. Meta agents (synthesis, triage, verification, validation, issue filing) stay on the global `--agent`. An unknown key or invalid agent aborts startup with the offending token named, and when overrides are active the estimated cost shown by `--dry-run` and the confirmation prompt is partitioned per agent alongside the active routing map. Example: `--agent opencode --agent-override security=claude,architecture=claude` ([#380](https://github.com/TheMorpheus407/RepoLens/issues/380)) - `--validate `: a decoupled post-audit validation pass that re-verifies an existing findings artifact with a flagship agent and drops its false positives, without re-running the expensive `DONE×3` lens scan. This lets you scan a large repo cheaply with a "Radar" agent (a local LLM, MiniMax via `opencode`, etc.) and then pay a flagship "Filter" `--agent` only for a fast verification pass. It ingests the RepoLens finding registry `findings.jsonl`, a `manifest.json` JSON array, or a single JSON finding object; sends each finding to the flagship with the repository on disk for context; keeps the confirmed findings (findings judged stale are kept but downranked — only false positives are dropped); and writes the cleaned set to `logs//validated-findings.jsonl`, printing explicit `Findings validated` / `Verified (survivors)` / `Dropped (false positives)` counts. `--validate` short-circuits the run before the lens fan-out and synthesizer and requires `--agent` (the flagship filter) and `--project` (the repo re-read for context). A missing, unreadable, or malformed input errors loudly without dispatching the agent; an empty artifact is a graceful no-op; and an agent failure exits non-zero rather than silently reporting that every finding was a false positive. This first slice emits the cleaned findings file only — it does not yet file the survivors as issues ([#379](https://github.com/TheMorpheus407/RepoLens/issues/379)) - `repolens.sh status ` and `status.json` now surface the **parent-run + attempts** model, so a run that took several passes reads as one parent that owns multiple attempts rather than a pile of look-alike directories. `status.json` carries a new `attempts` array — each entry has `attempt_id`, `status`, `why_stopped`, and `lenses_completed_this_attempt`, projected from `logs//attempts.json`; an absent, corrupt, or non-array record degrades to `[]` with no error. The human `status` render adds an `attempts: N (latest: )` line when a run has taken more than one pass, and a run that finishes after more than one attempt prints a one-line end-of-run note — `This run took N attempts (latest: ). Full continuation history: logs//attempts.json`. A single-attempt run shows no attempts line and no note, the flat `logs//` directory layout is unchanged (resume still reuses the same dir), and `--json` status output gains only the additive `attempts` field ([#377](https://github.com/TheMorpheus407/RepoLens/issues/377)) - Resume hint on abort: every resumable exit now prints a single stderr line telling you how to continue the run — beginning with `To resume this run: ./repolens.sh --project --agent --resume ` — with the real run id, project path, and agent filled in, followed by the current mode, local/forge boundary, output path, and `--yes` authorization when known. It appears on an interrupted run (SIGHUP/SIGINT/SIGTERM, exit `129`/`130`/`143`), a `rate-limit-pending` finalize (exit `3`) or phase rate-limit abort (exit `1`), and a no-progress or systemic-failure abort (exit `1`). A clean `finished`/`finished-empty` run and the degenerate-broken exit (`2`, a config/quality problem rather than a resumable one) print no hint, and the line is shown at most once per run. This surfaces the existing `--resume` flag at the moment it is needed instead of leaving a rate-limited or interrupted user to discover resume in the docs ([#372](https://github.com/TheMorpheus407/RepoLens/issues/372)) - Startup wall-clock estimate: the confirmation prompt and `--dry-run` preview now print an estimated wall-clock line for a full run — e.g. `Estimated wall-clock: ~4h 30m at --max-parallel 8` — so you can tell how long a fan-out will take before launching it (full runs have taken days, leaving users unsure whether a run was wedged or simply huge). When the estimate exceeds a threshold (default 24h, overridable via `REPOLENS_EST_WARN_HOURS`; `0` disables the warning), RepoLens prints a loud warning listing concrete levers to cut it down: raise `--max-parallel`, pick a faster/cheaper `--agent`, lower `--depth`, scope with `--domain`/`--focus`, or use `--max-issues N` for a spot check. The per-iteration guess feeding the estimate is tunable via `REPOLENS_EST_PER_ITER_SECS` (default `90` seconds). The line is omitted gracefully when no lenses are queued ([#359](https://github.com/TheMorpheus407/RepoLens/issues/359)) - Near-duplicate title-similarity thresholds are now operator-tunable via two environment variables, `DEDUPE_TITLE_SIM_PRIMARY` (default `8500` = 0.85) and `DEDUPE_TITLE_SIM_SECONDARY` (default `6000` = 0.60), both on the Jaccard ×10000 integer scale (`0`–`10000`). Lowering a threshold deduplicates more aggressively; a value above `10000` effectively disables that bar; non-numeric or negative values fall back to the default with a warning instead of crashing. `DEDUPE_TITLE_SIM_SECONDARY` applies only when two findings share the same non-empty location. When both are unset, behavior is byte-for-byte identical to before ([#353](https://github.com/TheMorpheus407/RepoLens/issues/353)) - `repolens.sh status ` human output now includes a `timing:` line, just after `progress:`, that surfaces the already-computed run timing: how long the run has been going and how much is estimated to remain, with a projected completion timestamp — e.g. `timing: ~1h 23m elapsed | ~4h 12m remaining (ETA 2026-04-17 11:39:00 UTC)`. So a user watching a multi-day run can tell roughly when it ends without reading `status.json` by hand. When the remaining time is not computable — nothing has completed, the run is in a terminal state, or the snapshot predates ETA tracking — the line shows `remaining unknown` (and `elapsed unknown` for an older snapshot with no timing data) instead of a bogus number. `--json` output is unchanged ([#352](https://github.com/TheMorpheus407/RepoLens/issues/352)) - `--local` runs now also write the canonical finding registry — `logs//final/findings.jsonl` and the flat `findings.csv` — indexing the `NNN-.md` finding files RepoLens dumps into the output directory. Previously a `--local` audit produced an unindexed tree of markdown with no machine-readable manifest; now each registry record's `markdown_path` resolves to its source file, the registry is written under `final/` (the output directory stays markdown-only), the build is non-fatal (a failure warns and the run still succeeds), and the end-of-run summary prints the index path ([#349](https://github.com/TheMorpheus407/RepoLens/issues/349)) - Per-lens wall-clock timing in `summary.json`: each non-skipped lens object now carries `started_at` and `completed_at` (ISO-8601 UTC) plus an integer `duration_seconds`, so you can tell which lenses dominate a multi-hour run. Skipped lenses report `null` timestamps and `0` duration ([#337](https://github.com/TheMorpheus407/RepoLens/issues/337)) - End-of-run time breakdown: every run now prints a `Time breakdown` section to stdout, just before the `=== RepoLens Run Summary ===` JSON dump, that rolls up the per-lens `duration_seconds`. It reports total wall time, total lens-seconds, the 10 slowest individual lenses, and per-domain duration totals (descending), all human-formatted (e.g. `2h 13m`). Runs whose `summary.json` predates per-lens timing degrade gracefully to a single `Time breakdown: no timing data` line instead of erroring ([#340](https://github.com/TheMorpheus407/RepoLens/issues/340)) - `--human-review` flag (with `REPOLENS_HUMAN_REVIEW` env fallback): the entry point for a forthcoming curated, noise-budgeted human-review digest that renders at finalize time instead of dumping every finding (a full run can emit hundreds). The flag takes no argument, accepts truthy/falsy values via the env fallback (`1`/`true`/`yes`/`on` enable, `0`/`false`/`no`/`off`/empty disable, any other value aborts startup with an error mentioning `REPOLENS_HUMAN_REVIEW`), honors CLI-over-env precedence, and shows the resolved value in `--dry-run` as `Human review: `. No digest is rendered yet — the bucketing, renderer, and held-back accounting land in follow-up issues ([#325](https://github.com/TheMorpheus407/RepoLens/issues/325)) - `--mode greenfield`: a spec-led backlog planning mode that requires `--spec`, runs the new Greenfield Planning domain, avoids repository code inspection, stays locked to `--rounds 1`, and creates one implementation-sized `[P0]`-`[P3]` issue per invocation until existing issues sufficiently cover the specification ([#283](https://github.com/TheMorpheus407/RepoLens/issues/283)) - `repolens.sh clean` subcommand: removes old run directories under `logs/` by age (`--older-than `, default `30d`) and count (`--keep-last `, default `50`), with `--dry-run`, `--force`, and `--remove-incomplete`. It uses a strictly positive selector — only run-id-named children of `logs/` carrying `summary.json` or `status.json` are ever considered — keeps resume candidates by default, and always keeps currently-live runs. The confirmation prompt is auto-skipped when stdin is not a terminal. Opt-in startup auto-retention runs the same prune in the background when `REPOLENS_AUTO_CLEAN=true` (`REPOLENS_RETENTION_DAYS` default `30`, `REPOLENS_KEEP_LAST` default `50`) and logs the resolved retention settings at INFO; off by default. Per-lens forensic `iteration-N-TIMESTAMP.txt` captures are now gzipped after a lens finishes, keeping the most recent `REPOLENS_ITERATION_KEEP` (default `3`) uncompressed — this data is never read by synthesis, verification, or `--resume` ([#251](https://github.com/TheMorpheus407/RepoLens/issues/251)) - Pricing staleness warning: when `config/agent-pricing.json` is more than 60 days old, the confirmation prompt and `--dry-run` output emit `[WARN] Pricing data is N days old — estimates may be inaccurate`. The warning is informational and does not block execution ([#249](https://github.com/TheMorpheus407/RepoLens/issues/249)) - `repolens.sh supersede ` subcommand: explicitly retires a run by writing a `.superseded` marker into `logs//`. A superseded run is skipped by `status` no-arg auto-selection (even when it is the newest) and becomes eligible for `clean` removal without `--remove-incomplete`, while a currently-live run is still never removed. The run id must be a direct `logs/` child and a genuine run dir; ids containing `/`, `.`, or `..` are rejected ([#312](https://github.com/TheMorpheus407/RepoLens/issues/312)) - GitLab support via `--forge glab`, including GitLab.com and custom HTTPS/SSH hosts, subgroup namespaces, issue filing and comments, labels, and paginated backlog reads ([#282](https://github.com/TheMorpheus407/RepoLens/pull/282)). ## [0.2.0] — 2026-05-24 ### Security - `--spec` file content is now sanitized to prevent prompt injection via ``/`` tag breakout — a malicious spec file could previously close the content boundary early and inject arbitrary top-level instructions into the agent prompt ([#50](https://github.com/TheMorpheus407/RepoLens/issues/50)) ### Fixed - Runs that create zero findings and mostly end at the per-lens `max-iterations` safety cap are now classified as broken instead of clean: `summary.json` records `health: "broken"` and `stopped_reason: "degenerate-no-findings"`, `status.json` reports `state: "failed"`, and the CLI exits `2` unless `REPOLENS_ALLOW_DEGENERATE=true`. Clean zero-finding runs now report `health: "no-findings"` with final state `finished-empty`; tune the broken-run percentage with `REPOLENS_DEGENERATE_THRESHOLD` ([#220](https://github.com/TheMorpheus407/RepoLens/issues/220)). - Persistent agent failures that do not match the rate-limit detector now stop early through a no-progress circuit breaker instead of burning the full per-lens iteration cap. Configure it with `REPOLENS_NO_PROGRESS_LIMIT` and `REPOLENS_NO_PROGRESS_MIN_BYTES`; affected lenses remain resumable with status `agent-no-progress`, and systemic failures report `stopped_reason=agent-degraded` ([#212](https://github.com/TheMorpheus407/RepoLens/issues/212)). - Agent rate-limit messages with parseable resume times now sleep within `REPOLENS_RATE_LIMIT_MAX_SLEEP`, retry the same lens once, and record `rate_limit_sleep_seconds`; unparseable, stale, too-far, or repeated rate limits still abort cleanly ([#115](https://github.com/TheMorpheus407/RepoLens/issues/115)) - Concurrent runs against the same repository now coordinate remote label setup, create only missing labels when supported, and reuse fresh matching bootstrap results while preserving normal issue-count behavior ([#186](https://github.com/TheMorpheus407/RepoLens/issues/186)) - Ctrl-C/TERM cleanup during parallel runs now returns after a bounded grace period, force-stopping unresponsive workers instead of waiting indefinitely. Configure the grace period with `REPOLENS_CLEANUP_GRACE` ([#114](https://github.com/TheMorpheus407/RepoLens/issues/114)) - `--hosted` service discovery now uses Docker Compose internal/container TCP ports for DAST URLs, falls back to exposed container ports when needed, and keeps published host ports as secondary context instead of pointing scanner containers at host-only NAT ports ([#83](https://github.com/TheMorpheus407/RepoLens/issues/83)) - `trademark-branding` lens (`--mode opensource`) no longer searches for hardcoded author-specific brand names when auditing third-party repositories — it now dynamically derives search terms from the audited repo's owner and name, plus any additional brand terms the agent discovers from the README or package manifest ### Changed - Agent invocation timeouts now use a layered resolver instead of one 6000-second fallback: agent-specific overrides (`REPOLENS_AGENT_TIMEOUT_CLAUDE`, `REPOLENS_AGENT_TIMEOUT_CODEX`, `REPOLENS_AGENT_TIMEOUT_OPENCODE`, `REPOLENS_AGENT_TIMEOUT_SPARK`, and `REPOLENS_AGENT_TIMEOUT_SPARC`) win over `REPOLENS_AGENT_TIMEOUT`, which wins over mode-specific `REPOLENS_AGENT_TIMEOUT_` values; every supported mode now defaults to 1800 seconds. `opencode/` uses the OpenCode override, and the Spark/SPARC aliases fall back to each other when only one alias variable is set ([#110](https://github.com/TheMorpheus407/RepoLens/issues/110), [#184](https://github.com/TheMorpheus407/RepoLens/issues/184)) ### Added - README and METHODOLOGY now document remote deploy mode end-to-end, including `--remote` examples, SSH key and ControlMaster behavior, remote troubleshooting, workstation-local forge actions, and the remote deploy security warning ([#201](https://github.com/TheMorpheus407/RepoLens/issues/201)). - Remote deploy authorization and normal pre-run confirmation prompts now show the selected `--remote` target before the operator starts the run. Labelled targets show both `Remote target: