Network-AI
Governance

Audit Log Schema

Audit log field reference, event types, and denial scoring data.

Source file: AUDIT_LOG_SCHEMA.md

Audit Log Schema — Network-AI v6.0.1

Network-AI writes a JSONL audit trail during permission management and swarm execution. This document describes every field and event type.


File Location

data/audit_log.jsonl

One JSON object per line. The file is append-only. Each entry is a complete, self-contained record — no dependencies between lines.

The CLI provides direct access without inspecting the file manually:

network-ai audit log            # print all entries (add --limit <n> to cap output)
network-ai audit tail           # live-stream new entries as they are appended
network-ai audit clear          # reset the log (irreversible)
network-ai --json audit log     # machine-readable output

Envelope (all events)

Every log entry uses the same outer structure:

{
  "timestamp": "2026-02-28T14:32:01.123456+00:00",
  "action":    "<event_type>",
  "details":   { ... }
}
FieldTypeDescription
timestampISO 8601 UTC stringWhen the event occurred
actionstringEvent type — see table below
detailsobjectEvent-specific payload — see per-event schemas

Event Types

actionEmitted byTrigger
permission_requestcheck_permission.pyAgent requests access to a resource
permission_grantedcheck_permission.pyRequest passes weighted scoring; token issued
permission_deniedcheck_permission.pyRequest fails scoring threshold
permission_revokedrevoke_token.pyToken explicitly revoked
ttl_cleanuprevoke_token.pyExpired tokens pruned from active_grants.json
budget_initializedswarm_guard.pyFederatedBudget ceiling set for a session
handoff_allowedswarm_guard.pyAgent-to-agent handoff passes all checks
handoff_blockedswarm_guard.pyAgent-to-agent handoff blocked by guard
safety_shutdownswarm_guard.pySwarm halted due to budget ceiling breach
initcontext_manager.pyProject context file created
update_decisionscontext_manager.pyArchitecture decision recorded
milestone_completecontext_manager.pyMilestone marked as completed
milestone_addcontext_manager.pyMilestone added to a bucket
update_stackcontext_manager.pyTech stack entry updated
update_goalscontext_manager.pyProject goal added
update_bannedcontext_manager.pyBanned approach recorded
update_projectcontext_manager.pyProject metadata updated
model.attemptGovernedModelGateway (lib/model-gateway.ts)A model served (or was attempted in) a governed request
model.refusalGovernedModelGateway (lib/model-gateway.ts)A model returned a classifier refusal (stop_reason:&quot;refusal&quot;); records the category

The model.* events are emitted by the TypeScript engine's GovernedModelGateway to its configured audit sink (e.g. SecureAuditLogger), capturing the refusal → fallback → billing lifecycle. Their details carry model, stopReason, refusalCategory, servedByFallback, creditRedeemed, costUsd, and usage.


Per-Event details Schemas

permission_request

{
  "agent_id":      "data_analyst",
  "resource_type": "DATABASE",
  "justification": "Need customer order history for Q1 sales report",
  "scope":         "read"
}
FieldTypeNotes
agent_idstringRequesting agent identifier
resource_typestringDATABASE, PAYMENTS, API, FILESYSTEM, EMAIL, CUSTOMER_DATA, INTERNAL_SERVICES
justificationstringFree-text justification, scored before grant
scopestring \nullOptional scope restriction (e.g. read, write)

permission_granted

{
  "token":         "grant_a1b2c3d4e5f67890abcdef1234567890ab",
  "agent_id":      "data_analyst",
  "resource_type": "DATABASE",
  "scope":         "read",
  "expires_at":    "2026-02-28T14:37:01.123456+00:00",
  "restrictions":  ["read-only", "no-schema-changes"],
  "granted_at":    "2026-02-28T14:32:01.123456+00:00"
}
FieldTypeNotes
tokenstringgrant_ + 32 hex chars (UUID4, no dashes)
agent_idstringAgent the token was issued to
resource_typestringResource access was granted for
scopestring \nullScope restriction, if provided
expires_atISO 8601 UTCToken expiry (default: 5 minutes from grant)
restrictionsstring[]Resource-type-specific restrictions applied
granted_atISO 8601 UTCSame as envelope timestamp

permission_denied

{
  "agent_id":      "untrusted_bot",
  "resource_type": "PAYMENTS",
  "reason":        "Combined evaluation score (0.31) below threshold (0.5).",
  "scores": {
    "justification": 0.25,
    "trust":         0.40,
    "risk":          0.90,
    "weighted":      0.31
  }
}
FieldTypeNotes
agent_idstringRequesting agent
resource_typestringResource that was denied
reasonstringHuman-readable denial reason
scores.justificationfloat 0–1Justification quality score (40% weight)
scores.trustfloat 0–1Agent trust level (30% weight)
scores.riskfloat 0–1Resource risk score (30% weight, inverted)
scores.weightedfloat 0–1Final combined score; threshold = 0.50

permission_revoked

{
  "token":    "grant_a1b2c3d4e5f67890abcdef1234567890ab",
  "agent_id": "data_analyst",
  "reason":   "manual revocation"
}

ttl_cleanup

{
  "removed_tokens": ["grant_abc...", "grant_def..."],
  "count":          2
}

budget_initialized

{
  "ceiling": 5000,
  "unit":    "tokens"
}

handoff_allowed

{
  "from_agent": "orchestrator",
  "to_agent":   "implementer",
  "task":       "implement payment service",
  "budget_remaining": 4120
}

handoff_blocked

{
  "from_agent": "implementer",
  "to_agent":   "orchestrator",
  "reason":     "budget_exceeded",
  "budget_used": 5100,
  "budget_ceiling": 5000
}

safety_shutdown

{
  "reason":         "budget_ceiling_breached",
  "budget_used":    5100,
  "budget_ceiling": 5000,
  "agent":          "rogue_agent"
}

Scoring Reference

Permission decisions use a three-factor weighted score:

FactorWeightSource
Justification quality40%Scored by score_justification() — checks specificity, context, action verbs, structural coherence, 16 prompt-injection patterns
Agent trust level30%Lookup in DEFAULT_TRUST_LEVELS dict; unknown agents default to 0.5
Resource risk (inverted)30%Base risk per resource type; high-risk resources require higher total score

Approval threshold: 0.50. Requests below this are logged as permission_denied.


Node.js Layer (TypeScript package)

When using the network-ai npm package directly, the SecureAuditLogger class in security.ts produces HMAC-SHA256-signed entries with the same envelope format plus a signature field. This is separate from the Python script layer described above.


v5.0 Event Types

The following event types were added in v5.0:

ActionSource ModuleDescription
approval_submittedApprovalInboxApproval request queued for human review
approval_decidedApprovalInboxHuman approved or rejected a pending request
job_enqueuedJobQueueJob added to the persistent priority queue
job_completedJobQueueJob finished (success or failure)
job_recoveredJobQueueCrashed job recovered and re-queued
transport_auth_failTransportLayerHMAC auth failed on inbound JSON-RPC message
vcr_record_startAgentVCRRecording session started
vcr_record_stopAgentVCRRecording session stopped
vcr_replayAgentVCRReplay of recorded session executed

v5.10 Event Types

The following event types were added in v5.11.0 (ClaimVerifier / Tier 1 agent honesty):

ActionSource ModuleDescription
shell_executeAgentRuntimeShell command executed; details.exitCode and details.timedOut record the real outcome. An ExecutionReceipt is attached to the ShellResult (signed by runtime, committed to exitCode + outputHash).
file_writeAgentRuntimeFile write completed; an ExecutionReceipt is attached to the FileResult committing to content hash.
trust_decayAuthGuardianAgent trust level decremented after N consecutive UNSUPPORTED_CLAIM violations; details.previousTrust, details.newTrust, and details.consecutiveViolations recorded.

v5.17 Perpetual Runtime Events

Opt-in. These go to separate JSONL files written by the CLI processes (or to your own sink through each component's onEvent callback), so a sentry can tail them read-only. Timestamps are epoch milliseconds in at. No secrets are ever written.

data/perpetual_audit.jsonl — one line per LeaseAuthority decision:

{ "source": "lease-authority", "at": 1800000000000, "action": "renew", "role": "runner", "runId": "research-swarm", "leaseId": "lease_3f…", "reason": null }
actionMeaning
issue / renewLease granted (first lease of a run / renewal)
refuseIssue or renewal refused (reason: stale heartbeat, run not active, invalid runId, …)
stopRenewal stopped by the policy (reason: budget ceiling, canary failure, failing health, sentry alert, end date, auto-renew off)
revoke / pause / resumeHuman or sentry control (role records who)
tightenPolicy narrowed (stricter only)
alertSentry or operator alert (reason: &lt;level&gt; from &lt;authenticated identity&gt;; &lt;level&gt; tripwire from sentry:proxy for decoy hits)
policyNewer operator-signed policy installed (reason: policy id)
checkpointOperator-signed human checkpoint accepted (runId, or reason: &quot;all runs&quot;) — v6.0.0
cosignThis authority co-signed a lease issued by another authority (k-of-n) — v6.0.0
capability-evalSigned capability evaluation installed (reason: &lt;suite&gt; &lt;evalId&gt;) — v6.0.0
accept-riskA failed posture check was accepted at startup with --accept-risk (check, detail) — v6.0.0

Since v6.0.0, refuse and stop reasons also include human checkpoint overdue, capability evaluation required…, authority halted: &lt;tripwire or sentry quorum&gt; (latched until an operator resume), attestation failures (attestation evidence missing, attestation nonce is stale or replayed, attested measurement is not on the policy list, …), and cosign: … for co-sign refusals (for example cosign: claims are not signed by their issuing authority). A tripwire revoke carries reason: &quot;tripwire reported by sentry:proxy&quot;.

data/egress_audit.jsonl — one line per EgressProxy decision:

{ "source": "egress-proxy", "at": 1800000000000, "outcome": "denied", "route": "pay", "leaseId": "lease_3f…", "runId": "research-swarm", "status": 403, "reason": "amount would exceed the per-run limit" }

outcome is forwarded, denied, or error; status is the HTTP status returned to the agent. Since v6.0.0 a request carrying a decoy credential is logged as denied with reason: &quot;tripwire: &lt;decoy label&gt;&quot; (the agent only sees a generic 403 forbidden), and an accept-risk line is written when the proxy starts despite a failed posture check.

VsockRelay / SpoolPuller (v6.0.0, via onEvent): { &quot;at&quot;, &quot;kind&quot;: &quot;request&quot; | &quot;drop&quot; | &quot;close&quot;, &quot;type&quot;?, &quot;reason&quot;? } — drop for frames that fail the fixed schemas, rate limits, or the in-flight cap; close for oversize or malformed frames.

Merkle audit (v6.0.0, optional): HashChainSink with { merkle } appends every chained event to a MerkleAuditLog; signed tree heads (nai-sth-v1: size, root, timestamp, logId) and consistency proofs go to an external witness.

data/sentry_&lt;id&gt;.jsonl — one line per finding: { &quot;sentry&quot;, &quot;detector&quot;, &quot;level&quot; (info|warning|critical), &quot;reason&quot;, &quot;agentId&quot;, &quot;runId&quot;, &quot;at&quot; }. Detectors: velocity, denied-access, prompt-injection, blackboard-poisoning, guarded-touch, canary-leak, goal-drift, tripwire (v6.0.0: decoy file touched or decoy credential used).

Runtime / blackboard entries gain one field when the Perpetual Runtime refuses a write: AgentRuntime file_write entries with result: &quot;blocked&quot; carry details.lease or details.guarded; LockedBlackboard logs BLACKBOARD_WRITE with action guarded and outcome denied (details.key, details.reason).


Retention & Privacy

  • The log is append-only. There is no built-in rotation — implement log rotation at the infrastructure level (e.g. logrotate, S3 lifecycle policy).
  • No PII is logged by default. Justification text is logged as-provided — avoid including PII in justification strings.
  • No API keys, tokens in cleartext, or sensitive resource content are logged.