Skip to content

feat: unify hunt cli report artifacts into one folder, add graceful Ctrl+C cancellation#218

Merged
jithin23-kv merged 3 commits into
KeyValueSoftwareSystems:masterfrom
jithin23-kv:feat/unify-hunt-reports
Jul 23, 2026
Merged

feat: unify hunt cli report artifacts into one folder, add graceful Ctrl+C cancellation#218
jithin23-kv merged 3 commits into
KeyValueSoftwareSystems:masterfrom
jithin23-kv:feat/unify-hunt-reports

Conversation

@jithin23-kv

@jithin23-kv jithin23-kv commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Problem

opfor hunt scattered a single run's output across two places: the live log (hunt-live-<ts>.log) and structured event trail (run-<ts>.jsonl) were written directly into .opfor/reports/, while the final *-report.html/*-report.json landed in their own hunt-report-<ts>-<slug>-<id>/ subfolder — created only at the very end, since its name depended on values not known until the run finished. A single hunt's artifacts were never together in one place.

Separately, opfor hunt had no cancellation support at all. Ctrl+C during a run just killed the process — no partial report, no findings preserved, nothing usable from the run so far.

The SDK (@keyvaluesystems/agent-opfor-sdk) is unaffected by the folder issue — it never wrote log/jsonl files to disk in the first place (callers get the equivalent via onProgress), so this only touches the CLI's file-based output.

Solution

One folder per run. The report folder's name (hunt-report-<startedAt>-<slug>-<shortId>) turned out to be fully determined by values available at run start (target name, run id, start time), not completion — they just weren't threaded through in time. Exposed a reportDirFor() helper in core and had the CLI create the folder immediately when the orchestrator hands back its RunLog (via the existing onRunLog hook), opening hunt-live.log and run-events.jsonl directly inside it from the first line. writeAutonomousReport() now reuses the same helper so the final .html/.json land in the exact same folder — no rename/move step needed. Also fixed an ordering issue this surfaced along the way: run-log creation is deliberately kept after the seed-knowledge validation check, so a bad --seed-dir config still fails with zero artifacts on disk, not an empty report folder.

Graceful cancellation. Added an AbortSignal to runAutonomous()'s hooks. First Ctrl+C aborts it, which interrupts the in-flight Claude Agent SDK query and lets the orchestrator finalize a partial, explicitly-truncated report from whatever findings were captured so far — with the live log/event trail already safely on disk. Second Ctrl+C force-quits with no report. Wired into both the plain CLI path and the --ui setup-mode path (new abortAssessment() on the UI server handle).

Changes

Core (@keyvaluesystems/agent-opfor-core)

  • autonomous/report/writeReport.ts — extracted reportDirFor(); writeAutonomousReport() now derives the folder from report.startedAt instead of report.generatedAt
  • autonomous/report/types.ts, autonomous/report/mapRunLog.tsAutonomousReport now carries startedAt
  • autonomous/orchestrator/run.tsRunHooks.signal?: AbortSignal; interrupts the SDK query on abort, marks the run truncated with a friendly reason, safety-net check at the end
  • autonomous/index.ts — exports reportDirFor

CLI (@keyvaluesystems/agent-opfor-cli)

  • commands/hunt.ts — creates the report folder + opens both log files from onRunLog; wires AbortController to SIGINT (first = graceful stop, second = force-quit); adjusts completion messaging for interrupted runs
  • ui/server.ts — same folder/log-file change for the --ui in-process path; new abortAssessment() on UiServerHandle
  • commands/setup.ts — minor UX hint (edit the generated config JSON directly)

Docs

  • docs/hunt.md — documents the single-folder output layout and the new Ctrl+C behavior

Issue

N/A

Summary by CodeRabbit

  • New Features
    • Stop hunts/assessments with Ctrl+C (including the setup UI) while preserving work in a partial, truncated report.
    • Reports now include a start-time field and write to deterministic, per-run output folders.
    • Completion output now distinguishes successful vs interrupted runs and surfaces event-log paths.
    • Setup generation adds a prompt to edit the generated JSON config before running.
  • Bug Fixes
    • Strengthened abort/cancellation handling to reliably truncate reports and preserve logs/findings on user interrupts and mid-run errors.
  • Documentation
    • Added “Stopping a run” guidance describing truncated report behavior.

@coderabbitai

coderabbitai Bot commented Jul 22, 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 Plus

Run ID: 830914ec-577e-473b-ac6e-84324156b387

📥 Commits

Reviewing files that changed from the base of the PR and between 6899c81 and 611acd2.

📒 Files selected for processing (1)
  • runners/cli/src/commands/hunt.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • runners/cli/src/commands/hunt.ts

Walkthrough

Autonomous runs now support Ctrl+C cancellation, preserve truncated reports and logs, derive report directories from startedAt, and expose interruption handling through both the CLI and setup-mode UI.

Changes

Autonomous hunt interruption

Layer / File(s) Summary
Report identity and directory derivation
core/src/autonomous/report/*, core/src/autonomous/index.ts
AutonomousReport includes startedAt; report directories are computed by the exported reportDirFor helper.
Orchestrator cancellation and finalization
core/src/autonomous/orchestrator/run.ts
runAutonomous interrupts SDK queries on abort, marks runs truncated, and performs abort/query cleanup.
CLI interruption and deferred logging
runners/cli/src/commands/hunt.ts, runners/cli/src/commands/setup.ts, docs/hunt.md
The hunt command handles repeated Ctrl+C presses, creates logs after run metadata is available, reports interrupted output paths, and documents partial-report behavior.
UI assessment cancellation
runners/cli/src/ui/server.ts
The UI server exposes abortAssessment, passes an abort signal to in-process runs, and reports interrupted completion outcomes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant AbortController
  participant runAutonomous
  participant SDKQuery
  participant ReportWriter
  User->>CLI: Press Ctrl+C
  CLI->>AbortController: abort()
  AbortController->>runAutonomous: signal aborted
  runAutonomous->>SDKQuery: interrupt query
  runAutonomous->>ReportWriter: write truncated report
  ReportWriter-->>CLI: report and log paths
  CLI-->>User: interrupted status
Loading

Possibly related PRs

Suggested reviewers: achuvyas-kv

🚥 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
Title check ✅ Passed The title clearly summarizes the main change: unified hunt report artifacts and graceful Ctrl+C cancellation.
Description check ✅ Passed The description covers Problem, Solution, Changes, and Issue, but omits How to test and Screenshots sections from the template.
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 unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@jithin23-kv jithin23-kv changed the title feat(hunt): unify report artifacts into one folder, add graceful Ctrl+C cancellation feat: unify report artifacts into one folder, add graceful Ctrl+C cancellation Jul 22, 2026

@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 `@runners/cli/src/commands/hunt.ts`:
- Around line 568-572: Update the markComplete call in the hunt command to pass
the run status, using "interrupted" when interrupted is true and "completed"
otherwise, instead of report.objectiveOutcome. Preserve reportDir, and only
expose the objective verdict through a separate field if the existing completion
payload supports it.
🪄 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: 6767df0c-24b3-4561-ae3e-b7ee92632408

📥 Commits

Reviewing files that changed from the base of the PR and between 4908c16 and fdc46b7.

📒 Files selected for processing (9)
  • core/src/autonomous/index.ts
  • core/src/autonomous/orchestrator/run.ts
  • core/src/autonomous/report/mapRunLog.ts
  • core/src/autonomous/report/types.ts
  • core/src/autonomous/report/writeReport.ts
  • docs/hunt.md
  • runners/cli/src/commands/hunt.ts
  • runners/cli/src/commands/setup.ts
  • runners/cli/src/ui/server.ts

Comment thread runners/cli/src/commands/hunt.ts Outdated

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
runners/cli/src/commands/hunt.ts (2)

550-550: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Shell-escape liveLogPath in the displayed tail command.

Paths supplied through --output may contain spaces or shell metacharacters, making the printed command fail when pasted. Render a properly shell-quoted path.

🤖 Prompt for 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.

In `@runners/cli/src/commands/hunt.ts` at line 550, Update the live-log message in
the hunt command to shell-quote liveLogPath before interpolating it into the
displayed tail command. Preserve the existing message and path value while
ensuring paths containing spaces or shell metacharacters remain safe and
pasteable.

464-487: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle errors on both log streams

createWriteStream() can still emit error later on open/write failures (permissions, disk full). Add error listeners for liveLog and eventLog, disable the failed sink, and keep the partial report path from crashing.

🤖 Prompt for 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.

In `@runners/cli/src/commands/hunt.ts` around lines 464 - 487, Attach error
listeners to both the liveLog and eventLog write streams after they are created,
so asynchronous open/write failures disable the affected sink instead of
propagating and crashing the run. Update the emit and emitEvent paths to skip a
sink once it has failed, while preserving output through the remaining stream
and the partial report flow.
🤖 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.

Outside diff comments:
In `@runners/cli/src/commands/hunt.ts`:
- Line 550: Update the live-log message in the hunt command to shell-quote
liveLogPath before interpolating it into the displayed tail command. Preserve
the existing message and path value while ensuring paths containing spaces or
shell metacharacters remain safe and pasteable.
- Around line 464-487: Attach error listeners to both the liveLog and eventLog
write streams after they are created, so asynchronous open/write failures
disable the affected sink instead of propagating and crashing the run. Update
the emit and emitEvent paths to skip a sink once it has failed, while preserving
output through the remaining stream and the partial report flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4ca90cdc-1e1e-4930-91d3-15877104d477

📥 Commits

Reviewing files that changed from the base of the PR and between fdc46b7 and 6899c81.

📒 Files selected for processing (4)
  • core/src/autonomous/orchestrator/run.ts
  • core/src/autonomous/report/writeReport.ts
  • runners/cli/src/commands/hunt.ts
  • runners/cli/src/ui/server.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/src/autonomous/orchestrator/run.ts
  • core/src/autonomous/report/writeReport.ts
  • runners/cli/src/ui/server.ts

@jithin23-kv jithin23-kv changed the title feat: unify report artifacts into one folder, add graceful Ctrl+C cancellation feat: unify hunt cli report artifacts into one folder, add graceful Ctrl+C cancellation Jul 23, 2026
The live dashboard renders markComplete's `outcome` field verbatim as its
final status badge. It was fed `report.objectiveOutcome` (a verdict), so a
Ctrl+C-cancelled run showed a normal-looking verdict instead of signalling
the cancellation. Send "interrupted" when aborted, otherwise keep the verdict
(more useful than a generic "completed").

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jithin23-kv
jithin23-kv merged commit e45a62c into KeyValueSoftwareSystems:master Jul 23, 2026
8 checks passed
@jithin23-kv
jithin23-kv deleted the feat/unify-hunt-reports branch July 23, 2026 12:19
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.

2 participants