nativeresponse

package
v0.0.13 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package nativeresponse is the per-target emission backend for the lifecycle pipeline: it maps the provider-neutral, constructor-built backend.HostResponse into the exact native continuation bytes a host reads from a command-hook's standard output.

Why a per-target backend (compiler lesson)

Semantic operation selection is decided once, in Go, at and after the shared middle-end (middleend.Derive). Everything downstream of that decision is a mechanical, typed emission step — the analogue of a compiler backend lowering one shared IR to per-target machine code. The native shape a host expects is therefore a property of the host's mandated extension medium:

  • OpenCode accepts the canonical Pasture proceed response through its generated plugin. Claude uses empty stdout: no hook directive. The canonical Pasture "proceed" token is not a documented Claude enum.
  • Codex's only lifecycle surface is a command-hook that reads exact bytes on stdin and interprets a JSON continuation object on stdout. Because the ABI is a native byte stream, the typed Go pipeline carries all the way to the final native bytes here rather than delegating encoding to a shell or Python shim.

Derivation of the exact Codex 0.153.0 native shapes

The two Codex shapes are derived from the pinned Codex 0.153.0 command-hook output contract (inspected source revision d6407d735942c7cfc996aa2bc7d0f97fc8f0e4bf):

  • hooks/src/schema.rs: HookUniversalOutputWire carries `continue` (a bool that defaults to true via default_continue) plus optional stopReason, suppressOutput, and systemMessage; the wire denies unknown fields.
  • hooks/src/engine/output_parser.rs: an empty or non-object stdout parses to "no directives"; a blocking PreToolUse hook is rejected unless continue==true (unsupported_pre_tool_use_universal), and a bare {"continue":true} yields decision=None, updatedInput=None → Proceed.

From those facts:

  • PreToolUse (blocking gate, SemanticGateConsultation): a Proceed decision is the minimal universal-continue object {"continue":true}. It carries no block decision, no permissionDecision, and no updatedInput, so the host proceeds with the tool call unchanged.
  • SessionStart (non-blocking observation, SemanticObservation): the native default continuation object {}. Every universal field defaults (continue defaults to true), and an observation contributes no hookSpecificOutput, so the empty object is the well-formed "observed; continue; no directives" value the host applies its defaults to.

The gate-versus-observation distinction is carried by the HostResponse itself: only a gate consultation produces a valid Proceed response, so a valid response selects the Proceed continuation and an invalid (zero) response selects the observation default.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CanonicalProceed

func CanonicalProceed(response backend.HostResponse) ([]byte, error)

CanonicalProceed returns the canonical Pasture host response bytes a host reads on standard output (OpenCode): the marshaled host response object for a valid gate Proceed decision, or nil (no stdout) for an observation that produced no decision. A gate proceed emits the canonical Pasture response and an observation emits nothing.

Callers MUST only invoke it after the durable receipt commit has completed, so that native bytes never precede persisted evidence.

func ClaudeContinuation added in v0.0.9

func ClaudeContinuation(response backend.HostResponse) ([]byte, error)

ClaudeContinuation is the current Claude dispatch adapter. Both an evaluated Proceed and an observation emit empty stdout. Refusals cannot pass through a byte-only adapter because their exit status and stderr would be lost.

func CodexContinuation

func CodexContinuation(response backend.HostResponse) ([]byte, error)

CodexContinuation returns the exact Codex native continuation bytes a host reads on standard output for one committed lifecycle event: {"continue":true} for a valid gate Proceed response and {} for an observation default. Codex's command-hook ABI reads a JSON continuation object on stdout for every configured hook, so the typed pipeline emits native bytes here. It is total over its input (no harness argument, no error path for a well-formed response), so the registry row references it directly for the Codex harness.

Callers MUST only invoke it after the durable receipt commit has completed, so that native bytes never precede persisted evidence.

func EncodeClaude added in v0.0.9

EncodeClaude is a pure Outcome encoder, not the current byte-only dispatch. An evidenced denial uses only the documented exit-2/stderr channel. Call it on the committed, capability-normalized response and preserve all streams.

func EncodeCodex added in v0.0.9

EncodeCodex preserves the observation and gate continuation identities. The current source contract does not prove a policy Deny channel. In particular, parser rejection of continue:false is not policy enforcement.

func EncodeOpenCode added in v0.0.9

func EncodeOpenCode(mapping pastureruntime.LifecycleEventMapping, response backend.HostResponse) (hostexit.Outcome, error)

EncodeOpenCode emits the canonical proceed body for an unenforced gate and the typed refusal for an evidenced named-surface row. A policy Deny on a row whose Response().AllowsDeny() is emitted as the canonical {decision:deny,reason} body at exit 0, which the generated permission hook enforces through the host effect mutation (internal/codegen/opencode_hooks.go). The capability alone does not enable the channel: this encoder is its required companion, and an evaluation fault is never dressed as a refusal — it carries no policy verdict, so it is rejected even where a denial would be emitted.

func FaultContinuation added in v0.0.9

func FaultContinuation(harness ir.HarnessID, semantic pastureruntime.EventSemantic) (hostexit.Continuation, error)

FaultContinuation returns the continuation a host reads as "you may continue" when pasture could NOT evaluate the event, for one harness and one declared event semantic. Pass the zero EventSemantic for an event this build does not declare.

The error names an unsupported harness. A caller that cannot name the host has no bytes to write, so it must fall back to the empty continuation rather than guess a shape.

func NormalizeDecision added in v0.0.9

func NormalizeDecision(mapping pastureruntime.LifecycleEventMapping, decision backend.Decision) (backend.Decision, error)

NormalizeDecision runs the same mechanical capability downgrade as encoding, but returns the value that must be persisted BEFORE commit. It evaluates no policy or authority. The subsequent encoder must receive this same decision.

Types

type UnsupportedResponseError added in v0.0.9

type UnsupportedResponseError struct {
	Event      string
	Surface    pastureruntime.HookSurface
	Capability pastureruntime.ResponseCapability
	Kind       backend.DecisionKind
}

UnsupportedResponseError means no source-backed native refusal channel is available. It is not a policy decision. The caller must use its fault path, not emit a guessed JSON object or treat the zero Outcome as exit 0.

func (*UnsupportedResponseError) Error added in v0.0.9

func (e *UnsupportedResponseError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL