Skip to content

feat: unified praxis + raptor freshness engine#63

Merged
anshulsao merged 6 commits into
mainfrom
feat/tool-freshness
Jul 16, 2026
Merged

feat: unified praxis + raptor freshness engine#63
anshulsao merged 6 commits into
mainfrom
feat/tool-freshness

Conversation

@anshulsao

@anshulsao anshulsao commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Keep raptor (and praxis itself) fresh — one unified freshness engine, not a raptor path bolted beside praxis's existing self-update.

Why unify

praxis already had a self-update posture (checkForUpdate, a 24h cache, compareSemver, the TTY nag box). Adding raptor as a separate internal/freshness would have duplicated the cache/comparator/renderer and drifted. Instead this generalizes the existing engine to a tool registry — praxis's own nag is migrated onto it, raptor is a second toolSpec. They share one cache, one comparator, one renderer, one throttle; they differ only in their spec (version resolver, releases repo, upgrade hint).

 tools := []toolSpec{ praxis, raptor }
   praxis: build version, gate=!isDevBuild, repo=praxis-cli,      hint=`praxis update` (self-updates)
   raptor: `raptor --version`, gate=installed, repo=raptor-releases, hint=`raptor upgrade` (nudge-only)
        │  shared: compareSemver · one per-tool cache file · fetch-with-retry · 24h throttle · one renderer
        ▼  surfaced in 4 places, both tools:
   ① praxis status --json → "tools":[…]   (freshCached = local-only; --refresh = live)
   ② praxis login         → one-line notice per stale tool
   ③ Execute() TTY nag    → one box per stale tool (raptor line is nudge-only)
   ④ driver skill + preamble → "if stale, offer `raptor upgrade` — ask first"

What's here (6 TDD tasks)

  1. selfupdate.LatestReleaseTagFor(repo) + one shared release-URL builder.
  2. Core refactor: toolSpec registry + checkTool + per-tool cache map; praxis's checkForUpdate() migrated onto checkTool(praxisSpec); raptor version from raptor --version, latest from Facets-cloud/raptor-releases.
  3. Execute nag loops the registry; printFreshnessBox renders each stale tool.
  4. status --json tools block (freshCached local-only default; freshLive on --refresh).
  5. praxis login stale notice + state.staleTools.
  6. Driver skill + execution preamble freshness step.

Guardrails

  • Nudge-only for raptor — praxis never runs raptor upgrade. praxis update stays praxis-only (self-replaces its binary).
  • Preserves all existing praxis behavior — dev-build skip, PRAXIS_NO_UPDATE_CHECK, 24h throttle, TTY nag, box format; every pre-existing update-check test stays green.
  • Best-effort everywhere — no network/exec/parse error blocks a command; status stays network-free by default.

Testing

  • go test ./... + go vet green; gofmt clean; goreleaser-check CI unaffected.
  • Live: status --refresh --json correctly reports raptor 0.1.81 < v0.1.82stale:true against real raptor-releases; praxis dev build correctly skipped.

Plan: docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added multi-tool freshness checks for both Praxis and Raptor, including per-tool stale notices and ask-first upgrade guidance.
    • status --json now includes a tools freshness array; --refresh performs live freshness checks and auth verification.
  • Bug Fixes
    • Improved freshness caching, throttling, and best-effort failure handling to avoid unnecessary network calls.
  • Documentation
    • Updated interactive guidance/meta-skill text for handling raptor whoami failures and stale Raptor upgrades.
  • Tests
    • Added/updated tests for tools freshness output, refresh/live behavior, and freshness parsing/timeouts.

anshulsao and others added 4 commits July 16, 2026 11:59
One multi-tool freshness engine (generalize cmd/update_check.go); praxis's own
self-update nag migrates onto it, raptor is a second toolSpec. Shared cache,
comparator, renderer, throttle. Nudge-only for raptor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Generalize the praxis update-check into a multi-tool freshness engine so
raptor freshness reuses it rather than fragmenting into a parallel path.

- internal/selfupdate: LatestReleaseTagFor(repo) + a shared releaseURL builder,
  so any repo's latest tag is fetchable (praxis-cli AND raptor-releases) through
  one path. praxis self-update URL now routes through the same builder.
- cmd/update_check.go: a toolSpec registry (praxis, raptor) drives one engine —
  shared compareSemver, one per-tool cache file (map keyed by tool), one
  fetch-with-retry, one 24h throttle. `checkForUpdate()` (praxis's nag) is now a
  thin call over `checkTool(praxisSpec)`. raptor: version from `raptor --version`,
  latest from Facets-cloud/raptor-releases; installed/checkable gating.
- Freshness{tool, installed, current, latest, stale} is the result surfaced to
  status/login/nag (next tasks).

All pre-existing update-check tests stay green (behavior preserved); added raptor
engine tests + per-tool cache-isolation test. Nudge-only: no code runs raptor upgrade.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Execute-time TTY nag now loops the tool registry (collectStaleNags) and
  renders each stale tool with one parameterized box (printFreshnessBox).
  raptor's line is nudge-only ('ask your user, then raptor upgrade — praxis
  won't run it').
- praxis status --json gains a 'tools' block from the shared engine: freshCached
  (local-only, no network) by default; --refresh forces freshLive. A cache-only
  freshMode keeps plain status network-free.
- Tests: raptor + praxis box rendering, nudge-only nag copy, status tools block,
  status --refresh live check.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- praxis login prints a one-line notice per stale tool (praxis/raptor) via the
  shared engine, recording state.staleTools; warms the cache for later status.
- praxis driver skill + execution preamble teach the freshness step: check
  status --json tools, offer `raptor upgrade` when stale, ask first (nudge-only).
- Guard tests for skill + preamble copy; noticeFreshness unit test.

Completes the unified praxis+raptor freshness feature (one engine, four surfaces).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c42e2e31-869b-4f03-83f9-25157623f2bb

📥 Commits

Reviewing files that changed from the base of the PR and between 9322415 and cc4883d.

📒 Files selected for processing (2)
  • cmd/update_check.go
  • cmd/update_check_test.go
💤 Files with no reviewable changes (1)
  • cmd/update_check_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/update_check.go

Walkthrough

Changes

The update system now evaluates Praxis and Raptor freshness independently through shared release-tag fetching, caching, and semver logic. Results appear in status and login JSON, interactive notices, asynchronous nags, and ask-first Raptor upgrade guidance.

Unified tool freshness

Layer / File(s) Summary
Repository release tag access
internal/selfupdate/selfupdate.go, internal/selfupdate/selfupdate_test.go, docs/superpowers/plans/...
Shared release URL construction and tag-only retrieval support arbitrary repositories while preserving Praxis release metadata retrieval.
Per-tool freshness engine
cmd/update_check.go, cmd/update.go, cmd/update_check_test.go, docs/superpowers/plans/...
Registered Praxis and Raptor specifications use version checks, per-tool cache entries, throttled retries, Raptor version detection, and tool-specific notices.
Status, login, and execute integration
cmd/root.go, cmd/status.go, cmd/status_test.go, cmd/login_setup.go, docs/superpowers/plans/...
Interactive execution, status, and post-auth setup consume cached or live freshness results and expose stale tools.
Raptor freshness guidance
internal/render/preamble.go, internal/render/preamble_test.go, internal/skillinstall/dummy.go, internal/skillinstall/dummy_test.go, docs/superpowers/plans/...
Raptor instructions inspect the tools status array and offer raptor upgrade only after confirmation.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant PraxisCLI
  participant FreshnessEngine
  participant GitHubReleases
  participant FreshnessCache
  User->>PraxisCLI: run status, login, or interactive command
  PraxisCLI->>FreshnessEngine: evaluate Praxis and Raptor
  FreshnessEngine->>FreshnessCache: read throttled per-tool entries
  FreshnessEngine->>GitHubReleases: fetch missing or live release tags
  GitHubReleases-->>FreshnessEngine: return release tags
  FreshnessEngine-->>PraxisCLI: return Freshness results
  PraxisCLI-->>User: render status data or stale notices
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: a unified freshness engine for praxis and raptor.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tool-freshness

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

@anshulsao
anshulsao marked this pull request as ready for review July 16, 2026 06:47
@anshulsao

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 9

🤖 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 `@cmd/login_setup.go`:
- Around line 261-264: Update the noticeFreshness call in the login setup flow
to execute with a short overall deadline covering all serial tool checks,
including retries and delays. Ensure the deadline stops further work and returns
cached or already completed freshness results, while preserving the existing
best-effort, non-fatal behavior and JSON handling.

In `@cmd/root.go`:
- Around line 52-58: Update the stale-nag collection flow around
collectStaleNags and notify so results are emitted per tool rather than only
after every freshness check completes. Ensure a stalled Raptor lookup or release
fetch cannot delay already-available Praxis notifications past the three-second
deadline, using per-tool deadlines or partial-result delivery while preserving
existing notification rendering.

In `@cmd/status_test.go`:
- Around line 81-104: Update TestStatusCmd_RefreshDoesLiveFreshness to
prepopulate the current Raptor cache entry before running statusCmd.RunE, using
the existing cache setup symbols and the local version “0.1.0”. Then retain the
fetchRaptorTag spy and assert it is called, ensuring the test distinguishes
--refresh’s live fetch from the empty-cache fallback.

In `@cmd/status.go`:
- Around line 71-78: Update the `statusRefresh` CLI flag help and long
description to state that `status --refresh` checks `/ai-api/auth/me` and
performs live tool-release freshness checks via `toolsFreshness`, rather than
describing it as auth-only. Keep the existing refresh behavior unchanged.

In `@cmd/update_check.go`:
- Around line 318-325: Update putCacheEntry to serialize the entire
readFreshnessCache, merge, and saveFreshnessCache sequence with a cross-process
lock, ensuring concurrent Praxis processes cannot overwrite each other’s tool
entries. Make saveFreshnessCache persist the updated cache via atomic rename,
while preserving the existing best-effort behavior.
- Around line 269-275: Update execRaptorVersion to create a short-lived timeout
context and invoke raptor --version through exec.CommandContext instead of
exec.Command, ensuring a stalled process returns "", false when the deadline
expires. Add a regression test that exercises a hung raptor binary and verifies
the function does not wait indefinitely.

In `@docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md`:
- Around line 98-102: Fix the nested Markdown code spans in the Execute()
notification description by replacing the outer backtick delimiters with a
non-conflicting presentation, while preserving the inline command spans for
`praxis update` and `raptor upgrade`.

In `@internal/render/preamble.go`:
- Around line 38-40: Correct the documented tools JSON shape: in
internal/render/preamble.go lines 38-40 and internal/skillinstall/dummy.go lines
166-170, instruct agents to locate the tools array entry where tool == "raptor"
and then inspect that entry’s stale field. Update the assertions in
internal/render/preamble_test.go lines 28-31 and
internal/skillinstall/dummy_test.go lines 40-46 to require this same array-entry
wording.

In `@internal/selfupdate/selfupdate_test.go`:
- Around line 81-85: Strengthen the 404 case in the releaseTagFrom test by
asserting that the returned error matches the specific “no releases published
yet” contract, checking its message or the appropriate typed sentinel rather
than only verifying err is non-nil. Keep the existing bad test server setup and
ensure unexpected errors fail the test.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 72a0bd07-026e-4ce1-9da1-71573b6accdd

📥 Commits

Reviewing files that changed from the base of the PR and between 4eff950 and 89f5061.

📒 Files selected for processing (14)
  • cmd/login_setup.go
  • cmd/root.go
  • cmd/status.go
  • cmd/status_test.go
  • cmd/update.go
  • cmd/update_check.go
  • cmd/update_check_test.go
  • docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md
  • internal/render/preamble.go
  • internal/render/preamble_test.go
  • internal/selfupdate/selfupdate.go
  • internal/selfupdate/selfupdate_test.go
  • internal/skillinstall/dummy.go
  • internal/skillinstall/dummy_test.go

Comment thread cmd/login_setup.go
Comment thread cmd/root.go
Comment thread cmd/status_test.go
Comment thread cmd/status.go
Comment thread cmd/update_check.go
Comment thread cmd/update_check.go
Comment thread docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md Outdated
Comment thread internal/render/preamble.go Outdated
Comment thread internal/selfupdate/selfupdate_test.go
Robustness around the new network/exec calls:
- Bound `raptor --version` with a context timeout (raptorVersionCmd seam) so a
  wedged raptor can't hang a login/nag check. Regression test for a hung binary.
- checkToolsBounded: run tool checks CONCURRENTLY with an overall deadline, used
  by login (caps offline latency) and the Execute nag (a slow raptor no longer
  suppresses a cached praxis nag; partial results returned).
- Atomic cache write (temp + rename) so a concurrent praxis never reads a torn
  cache; last-writer-wins is benign for a throttle (≤ one extra fetch).
- Correct the driver-skill + preamble copy: `tools` is a JSON ARRAY — find the
  entry whose `tool` is raptor and read its `stale`, not `raptor.stale`. Guards
  assert the wrong object-path is absent.
- status --refresh help/Long now state it also re-fetches tool latest versions.
- status --refresh test seeds a fresh raptor cache entry so it proves freshLive
  bypasses the cache (not just an empty-cache fetch).
- selfupdate: assert the 404 "no releases" error contract, not just err != nil.
- plan doc: remove nested code-span backticks (MD038).

go test ./... + vet green; live status --refresh still flags raptor stale.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@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: 1

🤖 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 `@cmd/update_check_test.go`:
- Around line 287-289: Remove the exec.LookPath guard from the timeout test in
raptorVersionCmd, since the command is replaced with a blocking stub and must
run even when Raptor is unavailable. Delete the resulting unused os/exec import
while preserving the existing timeout assertions and test setup.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51abfd5b-3053-4c1c-becd-f58f13701d76

📥 Commits

Reviewing files that changed from the base of the PR and between 89f5061 and 9322415.

📒 Files selected for processing (11)
  • cmd/login_setup.go
  • cmd/status.go
  • cmd/status_test.go
  • cmd/update_check.go
  • cmd/update_check_test.go
  • docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md
  • internal/render/preamble.go
  • internal/render/preamble_test.go
  • internal/selfupdate/selfupdate_test.go
  • internal/skillinstall/dummy.go
  • internal/skillinstall/dummy_test.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • internal/render/preamble_test.go
  • internal/skillinstall/dummy_test.go
  • cmd/status_test.go
  • internal/render/preamble.go
  • docs/superpowers/plans/2026-07-16-raptor-praxis-freshness.md
  • internal/selfupdate/selfupdate_test.go
  • cmd/login_setup.go
  • internal/skillinstall/dummy.go
  • cmd/update_check.go

Comment thread cmd/update_check_test.go Outdated
execRaptorVersion no longer does a separate exec.LookPath — a missing binary
already errors from CommandContext (same ("",false) result), so the timeout
test needs no skip guard and verifies the timeout on CI without raptor too.
Drops the redundant LookPath + the now-unused os/exec test import.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@anshulsao
anshulsao merged commit 50972a7 into main Jul 16, 2026
3 checks passed
@anshulsao
anshulsao deleted the feat/tool-freshness branch July 16, 2026 10:55
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