Skip to content

Harness: budget pauses close the run; plans, previews, tool drift and decoys - #7

Merged
imit merged 1 commit into
mainfrom
harness-parity
Sep 28, 2026
Merged

imit merged 1 commit into
mainfrom
harness-parity

Conversation

@imit

@imit imit commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

Brings Scute::Harness up to @scute/harness (TypeScript), including its fix that closes the run when Scute pauses the agent over budget. The plans, preview, drift and decoy endpoints are in open API PRs, not deployed yet.

What changes

  • Budget pause closes the run (live on the API).
    • A check answered deny with reason budget_exceeded means Scute paused the agent and ended its tasks.
    • The run now closes for good, like task_closed, and never mints a new task for the paused agent.
  • Plans. run.request_plan(calls, reason:) files several calls for one review (POST /agent/plans).
    • Steps are built from the tool specs, with each call's arguments as its details. The plan id is kept in the run's state.
    • Checks then send plan with the call's arguments as details, so each approved step runs once. An approval filed for the exact call still takes precedence.
    • run.plan_status reads the plan (GET /agent/plans/:id). A not_needed answer keeps no plan.
  • Previews. run.preview(tool, args) sends a dry run (dry_run: true) with no proofs and no plan. It doesn't count toward the budget guard, and it answers an Authz::Decision.
  • Tool drift. run.report_tools(definitions) sends { name, hash } per tool (POST /agent/tools).
    • The hash is a SHA-256 of { name, description ("" when missing), inputSchema (null when missing) }, with object keys sorted at every level.
    • It matches the TypeScript harness byte for byte (pinned by a test against hashes computed with the TS function). Only hashes leave the process.
  • Decoys. Scute::Guards.decoy(tools) refuses a call to a decoy tool ("I can't continue with this. A person will follow up.", reason decoy_called), reports it (POST /agent/decoys, Scute pauses the agent) and closes the run.
    • One deliberate difference from TypeScript: the run closes even when the report can't be sent.
    • report: false only refuses.

The new run methods live in two small modules (Harness::Plans, Harness::ToolReports), included in Run like HumanSteps.

Tests

  • Unit (fake API, Ruby 3.3): 95 examples, 0 failures (10 new, mirroring the TypeScript tests). RuboCop is clean. CI covers 3.2 to 3.4.
  • Live, bundle exec rake live against scute-api-v2: 82 examples, 0 failures, 5 pending.
    • The budget example now also checks that the run is closed, run.token answers task_closed, and no second task was minted.
    • The plan, preview, drift and decoy examples are written against the API shapes and skipped with "waits for the API deploy". They run once that hook is removed.
    • The fifth pending one is the existing skip: scute-ruby has no local decision engine for the policy snapshot.

README section ("Plans and previews", "Tool drift and decoys") and a CHANGELOG line.

… decoys

Brings Scute::Harness up to @scute/harness (TypeScript):

- A check answered deny with reason budget_exceeded (Scute paused the agent
  and ended its tasks) closes the run for good, like task_closed; it never
  mints a new task for the paused agent.
- run.request_plan(calls, reason:) files several calls for one review,
  built from the tool specs with each call's arguments as its details, and
  keeps the plan id in the run's state. Checks then send the plan and the
  call's arguments (a filed approval for the exact call still wins), so
  each approved step runs once. run.plan_status shows where it stands.
- run.preview(tool, args) is a dry run: no proofs, no budget used.
- run.report_tools(definitions) sends a SHA-256 per tool definition (name,
  description, input schema, keys sorted at every level), the same hash as
  the TypeScript harness; only hashes leave the process.
- Scute::Guards.decoy(tools) refuses a call to a decoy tool, reports it
  (Scute pauses the agent) and closes the run, even when the report can't
  be sent.

Unit tests against the fake API. The live suite checks the budget pause
closing the run; the plan, preview, drift and decoy examples are written
and skipped until the API deploys them. README section and CHANGELOG line.
@imit
imit merged commit cdd62ac into main Sep 28, 2026
3 checks passed
@imit
imit deleted the harness-parity branch September 28, 2026 19:59
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