NOIR
Core concepts

Approvals

Pause a precise effect, bind the decision to the requester, and resume safely after an interactive or text response.

Approvals are durable state, not a confirmation sentence in the prompt. Noir records the proposed input, requester, channel, expiration, and continuation needed to resume the exact paused operation.

Tool approvals

Set approval metadata on the tool or override it with policy:

const refund = tool({
  description: 'Refund a Stripe payment.',
  input: refundSchema,
  effect: 'write',
  approval: 'requester',
  retry: 'idempotent',
  approvalSummary: ({ paymentId, amount }) =>
    `Refund ${amount} on ${paymentId}`,
  execute: issueRefund,
})

When called, the runtime stores a pending approval and sends an approval output. Slack renders buttons; adapters without buttons can use text approval when their capabilities declare it.

Handler approvals

An existing framework can pause with noir.ask:

const approved = await noir.ask({
  name: 'publish-draft',
  title: 'Publish this draft?',
  details: summary,
  yes: 'Publish',
  no: 'Keep draft',
  expiresInMs: 30 * 60_000,
})

if (!approved) return 'Kept it as a draft.'

The promise resumes after the runtime processes a matching approval event. The decision must come from the requester recorded on the approval, not merely another member of the same channel.

Policy overrides

Plugin policy is scoped under the plugin name. Agent policy can override the assembled rule:

plugins: [stripe({ toolkit })],
policy: {
  'stripe.refund*': { approval: 'always', retry: 'idempotent' },
}

Design rules

  • Describe the exact effect, object, amount, and audience.
  • Set a meaningful expiration; expired approvals cannot resume.
  • Revalidate authorization after approval if external state can change.
  • Never treat message text such as “yes” as sufficient without the approval ID and requester binding.
  • Do not ask twice for the same resumed operation.
  • Keep the provider call idempotent even after a valid approval.

Approval makes a known operation permissible. It does not make arbitrary model output trusted or grant access beyond the specific request.

On this page