← Back to All Papers
PAPER I

The LogLine Protocol

Author: Dan Voulez

Institution: The LogLine Foundation

Version: 1.0.1

Date: February 05, 2026

Thesis: The log is not a record of execution. It is the prerequisite for execution.

Paper I — The LogLine Protocol

The Atomic Unit of Verifiable Action

Normative keywords per RFC 2119/8174 (MUST/SHOULD/MAY) apply.

The Story

March 2024. A major bank. $2.3 million gone in 47 minutes.

The forensic team spent six weeks reconstructing what happened. The logs showed API calls. The logs showed timestamps. The logs showed nothing useful about why any of it was authorized.

The attacker had compromised an AI assistant. The assistant had legitimate access. Every request looked normal—individually. The pattern that would have revealed the attack was invisible because the logs recorded what happened, not what was intended.

The attacker left no fingerprints because there was nowhere to leave them.

Now imagine a different architecture.

Before the first transfer, the AI assistant would have been required to sign this:


{
  "who": "did:logline:agent:assistant-7x3k",
  "did": "transfer",
  "this": {
    "from": "account:operating",
    "to": "account:external:9f8a2c",
    "amount": 47500,
    "currency": "USD"
  },
  "when": "2024-03-14T14:23:07.847Z",
  "confirmed_by": null,
  "if_ok": "emit:transfer.completed",
  "if_doubt": "escalate:treasury.human",
  "if_not": "emit:transfer.denied",
  "status": "pending"
}

This LogLine would hit the policy engine. The policy would check:

- Agent trajectory score: 0.23 (new agent, low trust)

- Transfer limit at this trajectory: $5,000

- Requested amount: $47,500

Decision: REQUIRE — human confirmation needed.

The LogLine becomes a Ghost. It persists. Signed. Timestamped. Evidence that the attack was attempted.

One Ghost is an anomaly. Forty-seven Ghosts in 47 minutes from the same agent? That's an alarm.

The attack fails because every attempt is a confession.

This is the LogLine Protocol.

I. The Inversion

Since 1945, every computing system has followed the same axiom:


Code runs → Log writes

Execution precedes registration. This gap between action and evidence is the root vulnerability of computation. In this gap:

- Logs are forged

- Logs are deleted

- Logs prove nothing about authorization

- Logs provide no cryptographic binding

The LogLine Protocol inverts this relationship.


Log writes → Code runs

Nothing happens unless it is first structured, signed, and committed as a LogLine.

The log is not a record of execution.

The log is the prerequisite for execution.


// logline-core/src/runtime.rs
// This is real code. Install it: cargo install logline-cli

use logline_core::{LogLine, Ledger, PolicyEngine, Decision};

pub struct Runtime {
    ledger: Ledger,
    policy: PolicyEngine,
}

impl Runtime {
    /// Execute an intent. The order is non-negotiable:
    /// 1. Create LogLine
    /// 2. Evaluate policy
    /// 3. Commit to ledger
    /// 4. THEN (and only then) execute
    pub fn execute(&mut self, intent: Intent) -> Result {
        // Step 1: Create the LogLine (the intent becomes structured)
        let logline = LogLine::from_intent(&intent)?;

        // Step 2: Evaluate policy BEFORE any execution
        let decision = self.policy.evaluate(&logline)?;

        // Step 3: Commit to ledger (this happens regardless of decision)
        let committed = self.ledger.append(logline, &decision)?;

        // Step 4: Execute only if ALLOW
        match decision {
            Decision::Allow => {
                let effect = self.execute_effect(&committed)?;
                Ok(Receipt::new(committed, effect))
            }
            Decision::Require { signers } => {
                // LogLine persists, waiting for consent
                Err(ExecutionError::ConsentRequired {
                    logline_cid: committed.cid(),
                    required_signers: signers,
                })
            }
            Decision::Deny { reason } => {
                // LogLine persists as Ghost
                Err(ExecutionError::Denied {
                    ghost_cid: committed.cid(),
                    reason,
                })
            }
        }
    }
}

The critical insight: the ledger append happens before the decision branch. Whether allowed or denied, the intent is recorded. The execution happens only after.

II. The 9-Field Tuple

Every action in a LogLine system is preceded by this structure:


┌─────────────────────────────────────────────────────────────────┐
│                    THE LOGLINE TUPLE                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  who           The actor                                        │
│                DID (did:method:id), Ed25519-bound               │
│                                                                 │
│  did           The verb                                         │
│                Canonical action from ALLOWED_ACTIONS registry   │
│                                                                 │
│  this          The payload                                      │
│                Typed JSON, validated against verb schema        │
│                                                                 │
│  when          The timestamp                                    │
│                ISO8601 UTC, nanosecond precision                │
│                                                                 │
│  confirmed_by  The consent                                      │
│                DID of approver (required for L3+ actions)       │
│                                                                 │
│  if_ok         Success commitment                               │
│                What happens when the action succeeds            │
│                                                                 │
│  if_doubt      Uncertainty protocol                             │
│                What happens on timeout or ambiguity             │
│                                                                 │
│  if_not        Failure commitment                               │
│                What happens when the action fails               │
│                                                                 │
│  status        Lifecycle state                                  │
│                DRAFT → PENDING → COMMITTED | GHOST              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

This structure is non-negotiable. Its rigidity is its security.

The Pact

These nine fields are not just a data structure. They are a contract.


who         → I identify myself
did         → I declare my intention
this        → I specify the terms
when        → I mark the moment
confirmed_by → I accept the witness
if_ok       → I commit to success
if_doubt    → I commit to uncertainty
if_not      → I commit to failure
status      → I accept the verdict

Before you act, you sign the pact.

There is no "let me try and see what happens." There is no action without commitment. The `if_ok`, `if_doubt`, and `if_not` fields are especially powerful—you cannot request anything without declaring what happens in every scenario.

This is why the system works. This is why disputes collapse. This is why trust is computable.

The format is the contract. The contract is the foundation.


// logline-core/src/tuple.rs

use serde::{Deserialize, Serialize};
use crate::{Did, Timestamp, ContentAddress};

/// The 9-field LogLine tuple. Every field is mandatory.
/// This is the atomic unit of verifiable action.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogLine {
    /// The actor initiating the action
    pub who: Did,

    /// The verb (canonical action identifier)
    pub did: ActionVerb,

    /// The payload (typed, schema-validated)
    pub this: serde_json::Value,

    /// UTC timestamp with nanosecond precision
    pub when: Timestamp,

    /// Consent provider (None until confirmed)
    pub confirmed_by: Option,

    /// Success commitment
    pub if_ok: Commitment,

    /// Uncertainty commitment
    pub if_doubt: Commitment,

    /// Failure commitment
    pub if_not: Commitment,

    /// Lifecycle state
    pub status: LogLineStatus,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LogLineStatus {
    Draft,      // Being composed
    Pending,    // Awaiting evaluation
    Committed,  // Executed successfully
    Ghost,      // Denied or expired
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Commitment {
    pub action: CommitmentAction,
    pub target: Option,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CommitmentAction {
    Emit(String),      // Emit an event
    Escalate(String),  // Escalate to handler
    Retry(u32),        // Retry with backoff
    Abort,             // Clean termination
}

impl LogLine {
    /// Compute the content address (identity) of this LogLine
    pub fn cid(&self) -> ContentAddress {
        let bytes = json_atomic::canonize(self);
        ContentAddress::from_blake3(&bytes)
    }

    /// Verify the LogLine signature
    pub fn verify(&self, public_key: &PublicKey) -> Result<(), SignatureError> {
        let bytes = json_atomic::canonize(self);
        public_key.verify(&bytes, &self.signature)
    }

    /// Transition to Ghost status
    pub fn ghost(mut self, reason: GhostReason) -> Self {
        self.status = LogLineStatus::Ghost;
        self.ghost_reason = Some(reason);
        self
    }
}

Read Full Paper on GitHub →