docs.businys.dev

Core features

Agent Lineage

A causal DAG (directed acyclic graph) that traces the full chain from human prompt to tool call result. Each node hashes its parent — tamper-evident by construction. Exportable as JSON or PDF for compliance documentation.

How it works

When a human sends a message to an agent, the agent makes tool calls to fulfil it. Each tool call may trigger sub-calls. Lineage captures this causal tree: who called what, in what order, with what parameters and result.

Each lineage node contains:

  • Node ID (UUID)
  • Parent node ID (null for the root human prompt)
  • Tool name, agent ID, server name
  • Input parameters, output, error status
  • Timestamp, duration
  • SHA-256 hash of parent_hash + tool_name + agent_id + input

The hash chain means the graph cannot be retroactively altered — the same integrity model as a blockchain, applied to AI agent audit trails. This satisfies EU AI Act Art. 12 record-keeping requirements for tamper-evidence.

Enabling lineage

server.tsts
import { createMCPProxy, MemoryLineageStore } from "@businys/ops"

const proxy = createMCPProxy({
  lineage: {
    store: new MemoryLineageStore(),
    // Optional: custom context extractor
    // getContext: (req) => ({ sessionId: req.headers["x-session-id"] }),
  },
})

Passing lineage context

To link a tool call to a parent (e.g. the human message that triggered it), pass the parent node ID in the X-Lineage-Parent request header:

client.tsts
// When sending the human message, create a root lineage node
// The agent framework passes the root node ID to child tool calls
fetch("http://localhost:3101/mcp", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Lineage-Parent": rootNodeId, // from LINEAGE_HEADERS
  },
  body: JSON.stringify(toolCallPayload),
})

Reading lineage chains

lineage.tsts
import { MemoryLineageStore, verifyLineage } from "@businys/ops"

const store = new MemoryLineageStore()

// Get the full chain for a call
const chain = await store.getChain(nodeId)
// chain.nodes — array of LineageNode in causal order
// chain.valid — boolean: hash chain verified

// Verify integrity
const valid = await verifyLineage(chain)

// Export as JSON for compliance documentation
const json = JSON.stringify(chain, null, 2)

LineageNode shape

FieldTypeDescription
idstringUUID for this node
parentIdstring | nullParent node ID, null for root
toolNamestringMCP tool name
agentIdstringAgent that made the call
serverNamestringMCP server name
inputRecord<string, unknown>Tool call arguments
outputstringTool call result
isErrorbooleanWhether the call returned an error
durationMsnumberCall duration in milliseconds
timestampnumberUnix timestamp ms
hashstringSHA-256 of parent_hash + tool_name + agent_id + input

Compliance use

Agent Lineage directly addresses EU AI Act Art. 13 (transparency — system output interpretable by deployers) and Art. 12 (record-keeping — tamper-evident logs). See comply.businys.dev/articles for the full article mapping.

To export a lineage chain as a compliance artifact:

export.tsts
const chain = await store.getChain(rootNodeId)
const artifact = {
  exportedAt: new Date().toISOString(),
  verified: await verifyLineage(chain),
  nodeCount: chain.nodes.length,
  chain: chain.nodes,
}
fs.writeFileSync("lineage-export.json", JSON.stringify(artifact, null, 2))