# Project Bundles

URL: https://docs.nexart.io/docs/concepts/project-bundles

Structured, cryptographically linked collections of CERs for multi-step and multi-agent workflows, verified as a single bundle.

## Overview

A Project Bundle is a structured collection of Certified Execution Records representing a multi-step workflow. Where a single CER proves one execution, a Project Bundle proves an entire sequence of executions and their relationships.

## Why Project Bundles Exist

Single CERs work well for isolated executions. But many real-world systems involve multiple steps:

- An agent that reasons, calls tools, then summarizes
- A pipeline that transforms data across several stages
- A workflow where each step depends on a previous output

Project Bundles give these multi-step processes a single verifiable artifact with one hash.

## What a Project Bundle Contains

- stepRegistry: ordered step metadata. Each entry contains a `stepId`, `sequence` number, `stepLabel`, and the step's `certificateHash`.
- embeddedBundles: the actual CERs, keyed by `stepId`. Each embedded bundle is a full CER with its own `certificateHash`.
- integrity: contains the `projectHash` and the algorithm used (`sha256-canonical-json`). Any change to any embedded CER, step metadata, or ordering produces a different `projectHash`.
- Project-level metadata: `projectBundleId`, `projectTitle`, timestamps (`startedAt`, `completedAt`), and optional fields like `projectGoal`, `projectSummary`, `appName`, and `tags`.

## Canonical Structure

This is the real stored shape of a Project Bundle artifact.

Project Bundle (cer.project.bundle.v1)

```
{
  "bundleType": "cer.project.bundle.v1",
  "projectBundleId": "pb_a1b2c3d4",
  "projectTitle": "Contract review pipeline",
  "protocolVersion": "1.2.0",
  "version": "0.1",
  "startedAt": "2026-04-01T10:00:00.000Z",
  "completedAt": "2026-04-01T10:02:30.000Z",
  "totalSteps": 2,
  "stepRegistry": [
    {
      "stepId": "step_1",
      "sequence": 0,
      "stepLabel": "Extract clauses",
      "certificateHash": "sha256:1111..."
    },
    {
      "stepId": "step_2",
      "sequence": 1,
      "stepLabel": "Summarize risks",
      "certificateHash": "sha256:2222..."
    }
  ],
  "embeddedBundles": {
    "step_1": {
      "bundleType": "cer.ai.execution.v1",
      "certificateHash": "sha256:1111...",
      "snapshot": { "model": "gpt-4", "inputHash": "sha256:...", "outputHash": "sha256:..." }
    },
    "step_2": {
      "bundleType": "cer.ai.execution.v1",
      "certificateHash": "sha256:2222...",
      "snapshot": { "model": "gpt-4", "inputHash": "sha256:...", "outputHash": "sha256:..." }
    }
  },
  "integrity": {
    "algorithm": "sha256-canonical-json",
    "projectHash": "sha256:ab12cd34ef56..."
  }
}
```

## projectHash

The `projectHash` is computed using `sha256-canonical-json` over the canonical content of the Project Bundle. It covers all embedded CERs, the step registry, ordering, and project metadata. Modifying any embedded CER, reordering steps, or changing metadata produces a different hash.

This is different from a `certificateHash`, which covers a single CER. See Certificate Hash vs Project Hash for a detailed comparison.

## Relationship to CERs

A Project Bundle does not replace CERs. Each entry in `embeddedBundles` contains a full CER that remains independently verifiable by its `certificateHash`. The Project Bundle adds:

- Step ordering and sequence via `stepRegistry`
- Step identity and labeling (`stepId`, `stepLabel`)
- A single project-level hash covering the entire workflow
- Optional project-level node receipt

## Defining Workflow Boundaries

NexArt does not automatically detect workflows. The developer explicitly defines the start and end of a workflow and decides which steps are included.

- A workflow starts when you begin recording CERs for a given process.
- Each meaningful step must create its own CER.
- The developer keeps the workflow context consistent and then collects the relevant CERs into a Project Bundle.
- The workflow ends when you build the Project Bundle from those CERs.

Developers often track a shared workflow or conversation identifier in their own system to group related steps. This is a developer-side concern, not a Project Bundle protocol requirement.

### Conceptual builder example

This is a simplified conceptual example showing the general flow. Refer to the AI Execution SDK docs for the exact current helper signatures.

Conceptual builder example

```
import { certify, createProjectBundle } from "@nexart/ai-execution";

// Step 1: create CER
const cer1 = await certify({
  model: "gpt-4",
  input: "Extract key clauses from the contract.",
  output: "Clause 1: ..., Clause 2: ..."
});

// Step 2: create CER
const cer2 = await certify({
  model: "gpt-4",
  input: "Summarize risks from: Clause 1: ..., Clause 2: ...",
  output: "Risk summary: ..."
});

// Build Project Bundle from collected CERs
// Step metadata (stepId, sequence, stepLabel) is included when building
const projectBundle = await createProjectBundle({
  projectTitle: "Contract review pipeline",
  steps: [
    { stepId: "step_1", stepLabel: "Extract clauses", cer: cer1 },
    { stepId: "step_2", stepLabel: "Summarize risks", cer: cer2 }
  ]
});

// projectBundle.integrity.projectHash is the verifiable hash
```

Important

NexArt guarantees integrity of what is recorded. It does not guarantee that all steps were recorded. Completeness is controlled by the developer.

### Best practices

- Record every meaningful step (LLM call, tool call, transformation).
- Keep step ordering explicit using `sequence` values.
- Keep workflow context consistent across steps in your application.
- Build the Project Bundle immediately after execution completes.
- Register it on the node if you want public lookup by `projectHash`.

## Using agent-kit (recommended)

For linear workflows, @nexart/agent-kit removes manual step tracking. Instead of creating CERs individually and assembling them, you use the workflow helpers:

- `startWorkflow()` begins a new workflow and generates a `workflowId`
- `step()` creates a CER per step. Each step gets its own `executionId`. The `workflowId` links them together.
- `finish()` builds the Project Bundle synchronously

`step()` records the step name as input and the function return value as output. Implicit closure state is NOT recorded.

Workflow with agent-kit (v0.3.0)

```
import { startWorkflow } from "@nexart/agent-kit";

const workflow = startWorkflow({ projectTitle: "Contract review" });

const clauses = await workflow.step("Extract clauses", async () => {
  return await llm.call("Extract key clauses...");
});

const risks = await workflow.step("Summarize risks", async () => {
  return await llm.call("Summarize risks from: " + clauses);
});

const bundle = workflow.finish();
// bundle.integrity.projectHash is the verifiable hash
```

Limitation

agent-kit v0.3.0 is designed for linear workflows. For complex DAGs or non-linear execution graphs, use the lower-level SDK helpers (`certify` + `createProjectBundle`).

## Verification

Project Bundles can be verified in two ways:

- On verify.nexart.io via `/p/:projectHash`. The site fetches the Project Bundle from the node-backed trust surface and runs verification independently in the browser.
- With the SDK: `verifyProjectBundle()` for Node/server environments, or `verifyProjectBundleAsync()` for browser-safe verification.

Verification checks:

- `projectHash` integrity
- Each embedded CER's `certificateHash`
- Optional node receipt at the project level

The node is not required for verification. It provides discovery and independent attestation. Integrity is proven by the hashes alone.

See How Verification Works and AI Execution SDK for details.
