← Back to docs

actor_kind · one primitive across human, agent, service, schedule

Every fasten audit row carries an actor_kind field. Its four values name the class of thing that emitted the row. A fatigued human approver is audited with the same primitive as a hallucinating model. This page explains why one enum, not four separate audit systems, and how membrane uses it for suppressed-claim provenance.

Audience. Compliance and policy owners asking "how do we audit humans, agents, and systems consistently" and engineering leads who need to answer "who touched entity X in the last 30 days" without union-ing four data sources.
user a human agent an AI model service a running program schedule a cron / timer

The four values

ValueRepresentsactor field carries
userA human whose action produced the row (approval, override, manual review).The user id (e.g. u_04217).
agentAn AI model that produced the row (belief update, tool call, response emission).The model id or agent id (e.g. credit-triage-v3).
serviceA running program that produced the row (a microservice writing durable state).The service id (e.g. payments-processor).
scheduleA scheduled job that produced the row (nightly reconciliation, retry sweep).The scheduler id and job name (e.g. cron:eod-close).

Four worked examples

1 · a manual approval (actor_kind = "user")

emit(
    code="LOAN_APPROVED",
    target="acct_042",
    actor="u_04217",         # the approver's id
    actor_kind="user",
    detail={"amount_cents": 500000, "override_reason": "long-standing customer"},
)

The row records that a human with id u_04217 approved the loan for acct_042. The detail.override_reason is queryable evidence. If a supervisor asks later "who override-approved this loan and what did they cite," the row is the answer.

2 · a hallucinating LLM (actor_kind = "agent")

emit(
    code="BELIEF_UPDATED",
    target="acct_042",
    actor="credit-triage-v3",
    actor_kind="agent",
    detail={"field": "risk_tier", "value": "low", "confidence": 0.62},
)

The model updated its belief about acct_042's risk tier. Membrane checks this against the system of record and suppresses the claim if it disagrees, but the attempted write is recorded, with actor_kind = "agent". When a regulator asks "did any AI decision touch this account," the query is ?target=acct_042&actor_kind=agent.

3 · a service-to-service call (actor_kind = "service")

emit(
    code="PAYMENT_CAPTURED",
    target="pay_01H9F2K7ZZ",
    actor="payments-processor",
    actor_kind="service",
    detail={"amount_cents": 1299, "currency": "USD"},
)

A backend service captured a payment. No human in the loop; no AI in the loop. Ordinary automated commitment.

4 · a scheduled job (actor_kind = "schedule")

emit(
    code="EOD_RECONCILED",
    target="ledger:2026-08-14",
    actor="cron:eod-close",
    actor_kind="schedule",
    detail={"tx_count": 18294, "delta_cents": 0},
)

The end-of-day reconciliation job closed the ledger cleanly. When something drifts, an operator queries ?actor=cron:eod-close for the sequence of scheduled runs.

Why not four separate audit systems

The alternative is separate tables (or worse, separate products) for user audit, agent audit, service audit, scheduler audit. Compliance teams end up with four query surfaces, four retention policies, four export formats, and no single answer to "who touched entity X in the last 30 days." The union query is the compliance officer's nightmare because it has to be repeated for every question.

One primitive on one substrate collapses all four into a single predicate. The query is one WHERE clause. Cross-actor invariants ("show me every entity where an AI decision preceded a human override within one hour") are one JOIN.

How membrane uses actor_kind

Membrane's source-authority ranking assigns different trust levels by actor_kind:

The OWASP LLM Top 10 · engineer's catalog shows this in the LLM01 (prompt injection) and LLM05 (improper output handling) sections: source-authority + actor_kind is why an injected instruction never commits to system state, only to the suppressed ledger.

Model provenance (P2-33) extends actor_kind = "agent" rows with three optional fields: model_id, model_version, prompt_hash. An auditor can then answer "which model version, on which prompt, produced this belief?" without a separate provenance store.

fasten

The audit substrate for distributed systems, and the belief layer for the AI agents on top of them.

Products
fastenmembranefasten fleet
Resources
DocsHow It WorksWhy fastenContact
© 2026 fasten · nerdAppLabs Software Solutions Pvt. Ltd.SDK Apache-2.0 · membrane & fleet commercial