nono already has a local audit model with append-only audit-events.ndjson, per-event hashes, a session hash chain/Merkle root, session metadata, and a global audit ledger. That local model is the right source of truth.
The missing upstream interface is a general way for code outside the core CLI modules to observe the same canonical audit records as they are written, without patching AuditRecorder or coupling to private pub(crate) types.
PR #831 / issue #798 moves proxy network audit events toward live local NDJSON recording by adding a proxy-specific NetworkAuditSink. That is useful and related, but it is event-type-specific. For downstream integrations, nono needs a broader open interface over the canonical audit event stream.
nono already has a local audit model with append-only audit-events.ndjson, per-event hashes, a session hash chain and Merkle root, session metadata, and a global audit ledger. That local model should remain the source of truth.
The missing upstream interface is a general way for integrations to observe the same canonical audit records as they are written, without patching AuditRecorder or coupling to private pub(crate) types.
PR #831 / issue #798 moves proxy network audit events toward live local NDJSON recording by adding a proxy-specific NetworkAuditSink. That is useful and related, but it is event-type-specific. A broader upstream interface would let integrations observe the complete audit event stream consistently.
Goals
- Provide a stable upstream interface for observing audit records as they are appended locally.
- Keep local audit recording, integrity summaries, and ledger append as the authoritative audit path.
- Support all current audit event classes, not only proxy network events.
- Preserve audit ordering and hash-chain semantics for consumers.
- Allow external crates or applications to implement their own buffering, export, alerting, or analysis behavior without changing core audit code.
- Keep
crates/nono policy-free unless there is a strong reason to expose a minimal shared type there.
Non-goals
- Do not replace local audit recording.
- Do not change the existing on-disk audit format as part of this issue.
- Do not let untrusted profiles or packs configure arbitrary external audit destinations.
Proposed direction
Add an upstream audit sink or fanout abstraction around the canonical local audit writer.
The interface should expose stable event metadata that allows consumers to correlate and verify ordering, including the session identifier, event sequence, event type, event hash, chain hash, and canonical event payload.
The sink should be called only after the local record has been successfully appended and flushed. Local audit remains authoritative; sink failures should not corrupt local audit state.
This issue should settle the shape and ownership of the open interface before choosing concrete method signatures or data structures.
Event coverage
The interface should cover all current audit event classes:
- session start
- session end
- capability approval decisions
- URL-open requests
- proxy network events
- command-policy / ETI events
Integration points
nono-cli::audit_integrity::AuditRecorder should likely own the fanout point because it already produces the canonical local audit records and hash-chain state.
nono-cli::supervised_runtime should attach any configured sinks when it constructs the local recorder. Sink configuration should be trusted parent-side configuration, not sandboxed child state.
nono-cli::rollback_runtime::finalize_supervised_exit should notify sinks when final session metadata and audit integrity data are known, while preserving the existing ledger and attestation flow.
nono-proxy should continue to work standalone when no sink is attached. If live proxy event streaming is available, those events should enter the same canonical audit stream without duplicate recording at finalization.
Error and blocking semantics
Default behavior should be fail-open for external sinks:
- A sink failure must not grant extra sandbox permissions.
- A sink failure must not abort an in-flight proxy request.
- A sink failure must not prevent local audit recording.
- A sink failure should be visible through
tracing::warn and, where appropriate, final session metadata.
Any fail-closed behavior should be explicit, separately configured, and carefully reviewed because it changes runtime availability semantics.
Privacy and configuration constraints
Audit payloads can include command arguments, paths, hostnames, URL origins, process IDs, and denial reasons. The open interface should document that sinks receive sensitive metadata and are responsible for any downstream filtering or redaction policy. #782 adds a scrubber API
Configuration for external sinks should come from trusted user, administrator, or embedding application configuration. It should not be controlled by untrusted profiles, packs, or sandboxed children.
Audit payloads can include command arguments, paths, hostnames, URL origins, process IDs, and denial reasons. The open interface should document that sinks receive sensitive metadata and are responsible for any downstream redaction policy.
Compatibility
- No on-disk format change is required.
- Existing
audit-events.ndjson verification should continue to work unchanged.
- Existing
nono audit show / nono audit verify behavior should not depend on any sink.
- Existing standalone
nono-proxy behavior should remain unchanged when no sink is attached.
nonoalready has a local audit model with append-onlyaudit-events.ndjson, per-event hashes, a session hash chain/Merkle root, session metadata, and a global audit ledger. That local model is the right source of truth.The missing upstream interface is a general way for code outside the core CLI modules to observe the same canonical audit records as they are written, without patching
AuditRecorderor coupling to privatepub(crate)types.PR #831 / issue #798 moves proxy network audit events toward live local NDJSON recording by adding a proxy-specific
NetworkAuditSink. That is useful and related, but it is event-type-specific. For downstream integrations,nononeeds a broader open interface over the canonical audit event stream.nonoalready has a local audit model with append-onlyaudit-events.ndjson, per-event hashes, a session hash chain and Merkle root, session metadata, and a global audit ledger. That local model should remain the source of truth.The missing upstream interface is a general way for integrations to observe the same canonical audit records as they are written, without patching
AuditRecorderor coupling to privatepub(crate)types.PR #831 / issue #798 moves proxy network audit events toward live local NDJSON recording by adding a proxy-specific
NetworkAuditSink. That is useful and related, but it is event-type-specific. A broader upstream interface would let integrations observe the complete audit event stream consistently.Goals
crates/nonopolicy-free unless there is a strong reason to expose a minimal shared type there.Non-goals
Proposed direction
Add an upstream audit sink or fanout abstraction around the canonical local audit writer.
The interface should expose stable event metadata that allows consumers to correlate and verify ordering, including the session identifier, event sequence, event type, event hash, chain hash, and canonical event payload.
The sink should be called only after the local record has been successfully appended and flushed. Local audit remains authoritative; sink failures should not corrupt local audit state.
This issue should settle the shape and ownership of the open interface before choosing concrete method signatures or data structures.
Event coverage
The interface should cover all current audit event classes:
Integration points
nono-cli::audit_integrity::AuditRecordershould likely own the fanout point because it already produces the canonical local audit records and hash-chain state.nono-cli::supervised_runtimeshould attach any configured sinks when it constructs the local recorder. Sink configuration should be trusted parent-side configuration, not sandboxed child state.nono-cli::rollback_runtime::finalize_supervised_exitshould notify sinks when final session metadata and audit integrity data are known, while preserving the existing ledger and attestation flow.nono-proxyshould continue to work standalone when no sink is attached. If live proxy event streaming is available, those events should enter the same canonical audit stream without duplicate recording at finalization.Error and blocking semantics
Default behavior should be fail-open for external sinks:
tracing::warnand, where appropriate, final session metadata.Any fail-closed behavior should be explicit, separately configured, and carefully reviewed because it changes runtime availability semantics.
Privacy and configuration constraints
Audit payloads can include command arguments, paths, hostnames, URL origins, process IDs, and denial reasons. The open interface should document that sinks receive sensitive metadata and are responsible for any downstream filtering or redaction policy. #782 adds a scrubber API
Configuration for external sinks should come from trusted user, administrator, or embedding application configuration. It should not be controlled by untrusted profiles, packs, or sandboxed children.
Audit payloads can include command arguments, paths, hostnames, URL origins, process IDs, and denial reasons. The open interface should document that sinks receive sensitive metadata and are responsible for any downstream redaction policy.
Compatibility
audit-events.ndjsonverification should continue to work unchanged.nono audit show/nono audit verifybehavior should not depend on any sink.nono-proxybehavior should remain unchanged when no sink is attached.