Skip to main content
This is a preview/beta feature. Further changes are expected.

Overview

chainloop trace hooks into Claude Code and Git to automatically capture what happens during AI-assisted coding sessions — models used, tokens consumed, tools invoked, code changes produced, and more. Every git push bundles this data into a cryptographically signed attestation using the CHAINLOOP_AI_CODING_SESSION material type. This gives security and engineering teams full visibility into how AI agents contribute to your codebase, without changing how developers work.
chainloop trace currently supports Claude Code sessions. Support for additional AI coding agents is planned.

Why trace AI coding sessions

AI coding agents are productive — but without visibility, teams can’t answer basic questions:
  • Which commits were AI-assisted, and what models were used?
  • How much did a session cost in tokens and dollars?
  • What tools did the agent invoke, and how many times?
  • What code changes did the agent produce?
chainloop trace answers all of these automatically. Combined with Chainloop’s policy engine, you can enforce governance rules — for example, requiring that AI-assisted commits use approved models or stay within token budgets.

How it works

chainloop trace init installs lightweight hooks into both Git and Claude Code that work together:
  1. When a Claude Code session starts, a hook records the session ID and begins copying session data (the JSONL transcript) into .git/chainloop-trace/.
  2. When you commit, a post-commit hook records the commit SHA, message, and which Claude Code session produced it.
  3. When you push, a pre-push hook parses all captured session data, correlates commits with sessions, and creates a signed Chainloop attestation with the full evidence.
After the push, the session data in .git/chainloop-trace/ is cleaned up automatically. The attestation lives in Chainloop, tied to your project and workflow.
AI Coding Session

Getting started

Prerequisites

Initialize tracing

Run chainloop trace init from your repository root:
chainloop trace init --project my-project
This command:
  1. Creates the .git/chainloop-trace/ directory for local state
  2. Installs Git hooks (post-commit and pre-push)
  3. Installs Claude Code hooks (SessionStart, PreToolUse, and SessionEnd) into .claude/settings.json
If you already have Git hooks in place, chainloop trace backs them up automatically and chains them — your existing hooks continue to run as before.
If your repository has a .chainloop.yml file with a projectName field, you can omit the --project flag — the CLI resolves it automatically.

Work as usual

Once initialized, there’s nothing else to do. Write code with Claude Code, commit, and push. The hooks handle everything in the background.
# Start a Claude Code session and work on your code
# ... make changes, commit ...

git push origin my-branch
# pre-push hook automatically creates the attestation
The pre-push hook only creates attestations for commits that are linked to a Claude Code session. Regular (non-AI-assisted) commits pass through without any overhead.

Remove tracing

To uninstall all hooks and clean up local state:
chainloop trace uninstall
This removes the Git hooks, the Claude Code hooks from .claude/settings.json, and the .git/chainloop-trace/ directory. If existing hooks were backed up during installation, they are restored.

Hooks in detail

Git hooks

HookWhen it runsWhat it does
post-commitAfter every git commitRecords commit SHA, message, timestamp, and active session ID to .git/chainloop-trace/commits/
pre-pushBefore every git pushParses all session data, builds evidence, and pushes a signed attestation to Chainloop
Both hooks are non-blocking — if they fail, they log a warning but never prevent the commit or push from succeeding.

Claude Code hooks

HookWhen it runsWhat it does
SessionStartWhen a Claude Code session beginsRecords the session ID and starts copying session JSONL data
PreToolUseBefore each tool invocationEnsures the session is tracked (handles cases where SessionStart was missed)
SessionEndWhen a Claude Code session endsPerforms a final copy of the session JSONL and marks the session as inactive
These hooks are configured in .claude/settings.json:
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "chainloop trace hook claude session-start"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "chainloop trace hook claude pre-tool-use"
          }
        ]
      }
    ],
    "SessionEnd": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "chainloop trace hook claude session-end"
          }
        ]
      }
    ]
  }
}

What gets captured

The CHAINLOOP_AI_CODING_SESSION evidence includes:

Session metadata

  • Session ID, start/end time, and duration
  • Claude Code version and session slug

Model and token usage

  • Primary model and all models used during the session
  • Input, output, and cache tokens
  • Estimated cost in USD (based on published Anthropic pricing)

Tool usage

  • Every tool the agent invoked (Read, Write, Edit, Bash, Grep, etc.)
  • Invocation count per tool and total invocations

Conversation summary

  • Total messages, user messages, and assistant messages

Subagent details

  • Each subagent spawned: type, description, and token usage

Git context

  • Repository URL, branch, and working directory
  • Commit range (start SHA to end SHA) and full list of commits
  • Merge-base detection against main/master

Code changes

  • Files modified, created, deleted, renamed, or copied
  • Lines added and removed
  • Per-file status breakdown

Evidence structure

{
  "schema_version": "1.0",
  "agent": {
    "name": "claude-code",
    "version": "1.0.0"
  },
  "session": {
    "id": "abc123-...",
    "started_at": "2026-03-31T10:00:00Z",
    "ended_at": "2026-03-31T10:45:00Z",
    "duration_seconds": 2700
  },
  "model": {
    "primary": "claude-opus-4-6",
    "provider": "anthropic",
    "models_used": ["claude-opus-4-6", "claude-haiku-4-5-20251001"]
  },
  "usage": {
    "input_tokens": 125000,
    "output_tokens": 42000,
    "total_tokens": 167000,
    "estimated_cost_usd": 1.675
  },
  "tools_used": {
    "summary": [
      { "tool_name": "Read", "invocation_count": 23 },
      { "tool_name": "Edit", "invocation_count": 12 },
      { "tool_name": "Bash", "invocation_count": 8 }
    ],
    "total_invocations": 43
  },
  "git_context": {
    "repository": "[email protected]:acme/backend.git",
    "branch": "feat/new-api",
    "commit_start": "a1b2c3d",
    "commit_end": "e4f5g6h",
    "commit_count": 3
  },
  "code_changes": {
    "files_modified": 5,
    "files_created": 2,
    "lines_added": 240,
    "lines_removed": 45
  }
}

Applying policies

Define CHAINLOOP_AI_CODING_SESSION in your contract to attach policies to traced sessions:
contract.yaml
apiVersion: chainloop.dev/v1
kind: Contract
metadata:
  name: ai-session-governance
spec:
  materials:
    - type: CHAINLOOP_AI_CODING_SESSION
      name: ai-coding-session
  policies:
    materials:
      - ref: file://check-approved-models.yaml

Example: restrict to approved models

check-approved-models.yaml
apiVersion: chainloop.dev/v1
kind: Policy
metadata:
  name: check-approved-models
  description: Ensure AI coding sessions only use approved models
spec:
  policies:
    - kind: CHAINLOOP_AI_CODING_SESSION
      embedded: |
        package main

        import rego.v1

        valid_input if {
          input.data.model.models_used
        }

        approved_models := {"claude-opus-4-6", "claude-sonnet-4-6"}

        violations contains msg if {
          valid_input
          some model in input.data.model.models_used
          not model in approved_models
          msg := sprintf("Model '%s' is not approved for AI coding sessions.", [model])
        }

Example: enforce token budget

check-token-budget.yaml
apiVersion: chainloop.dev/v1
kind: Policy
metadata:
  name: check-token-budget
  description: Flag sessions that exceed a token budget
spec:
  policies:
    - kind: CHAINLOOP_AI_CODING_SESSION
      embedded: |
        package main

        import rego.v1

        valid_input if {
          input.data.usage.total_tokens
        }

        max_tokens := 500000

        violations contains msg if {
          valid_input
          input.data.usage.total_tokens > max_tokens
          msg := sprintf("Session used %d tokens, exceeding the %d token budget.", [input.usage.total_tokens, max_tokens])
        }

Inspecting traces in the platform

Once a trace attestation has been pushed, you can inspect it directly in the Chainloop Web UI. Navigate to the workflow run that contains the CHAINLOOP_AI_CODING_SESSION material.

Rendered view

The platform renders a structured summary of the session — model usage, token consumption, estimated cost, tool invocations, code changes, and git context — all in an easy-to-read format.
AI Coding Session material view showing session metadata, token usage, cost, git context, code changes, and tool invocations

Raw view

Switch to the raw view to see the full JSON evidence as captured by the hooks. This is useful for debugging policies or understanding the exact data available for Rego evaluation.
AI Coding Session raw JSON view showing the full evidence schema with session, git context, and code changes
You can inspect any CHAINLOOP_AI_CODING_SESSION material the same way you inspect other evidence types — click on the material in the workflow run details to toggle between rendered and raw views.

Relationship to AI config collection

chainloop trace and the AI config collector are complementary:
AI Config CollectorChainloop Trace
What it capturesStatic configuration files (CLAUDE.md, settings, MCP config, rules, skills)Runtime session data (tokens, tools, code changes, costs)
When it runsDuring chainloop attestation init --collectors aiagentAutomatically on every git push via hooks
Material typeCHAINLOOP_AI_AGENT_CONFIGCHAINLOOP_AI_CODING_SESSION
Use caseGovernance over how agents are configuredVisibility into what agents actually did
Use both together for full coverage: the config collector ensures agents are set up correctly, while trace ensures they behave as expected at runtime.