> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.nunu.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# List Knowledge Files

> List knowledge files for a project. Always returns project-scope files; conditionally includes agent- and/or test-case-scope files when their IDs are passed as query parameters.

<Info>
  **Permission Required**: any API key scoped to the requested project
</Info>

<Note>
  Knowledge endpoints are served by the **bouncer** service at
  `https://bouncer.nunu.ai`, not the main `nunu.ai/api/v1` host. Use the same
  `X-Api-Key` header for authentication.
</Note>

Knowledge files are user-uploaded reference material (design docs, specs,
guides, etc.) that nunu agents can read while running. Files are organized by
**scope**:

| Scope       | Path on storage                       | Visible to                       |
| ----------- | ------------------------------------- | -------------------------------- |
| `project`   | `{projectId}/project/`                | Every run in the project         |
| `agent`     | `{projectId}/agent/{agentId}/`        | Runs that use the given agent    |
| `test_case` | `{projectId}/test_case/{testCaseId}/` | Runs that execute the given test |

This endpoint **always** returns project-scope files, and optionally appends
agent- and/or test-case-scope files when their IDs are passed as query
parameters.

## Path Parameters

<ParamField path="projectId" type="string" required>
  The nunu.ai project ID. Must match the project the API key is scoped to.
</ParamField>

## Query Parameters

<ParamField query="agent_id" type="string">
  Include files from `agent/{agent_id}/` in the response.
</ParamField>

<ParamField query="test_case_id" type="string">
  Include files from `test_case/{test_case_id}/` in the response.
</ParamField>

<ParamField query="include_metadata" type="boolean" default="false">
  When `true`, attach the parsed metadata (`description`, `summary`,
  `keywords`) for each file. Metadata is stored alongside each file as a
  hidden `.{name}.meta.json` sidecar.
</ParamField>

## Response

<ResponseField name="projectId" type="string" required>
  Echo of the path parameter.
</ResponseField>

<ResponseField name="count" type="integer" required>
  Total number of files across all included sections.
</ResponseField>

<ResponseField name="sections" type="Section[]" required>
  One section per scope returned. The `project` section is always present;
  other sections are only present when the corresponding query parameter is
  set.

  <Expandable title="Section properties">
    <ResponseField name="sections[].scope" type="string">
      One of `project`, `agent`, `test_case`.
    </ResponseField>

    <ResponseField name="sections[].id" type="string">
      The agent or test case ID. Omitted for the `project` section.
    </ResponseField>

    <ResponseField name="sections[].count" type="integer">
      Number of files in this section.
    </ResponseField>

    <ResponseField name="sections[].files" type="File[]">
      Files in this section. See [File Object](#file-object) below.
    </ResponseField>
  </Expandable>
</ResponseField>

### File Object

<ResponseField name="filename" type="string" required>
  Basename of the file (no directory prefix).
</ResponseField>

<ResponseField name="path" type="string" required>
  Path of the file relative to the scope root (may include subdirectories).
</ResponseField>

<ResponseField name="size" type="integer" required>
  File size in bytes.
</ResponseField>

<ResponseField name="uploaded" type="string" required>
  ISO 8601 timestamp when the file was last written.
</ResponseField>

<ResponseField name="etag" type="string" required>
  Object ETag.
</ResponseField>

<ResponseField name="metadata" type="object">
  Only present when `include_metadata=true` and a sidecar metadata file exists.

  <Expandable title="metadata properties">
    <ResponseField name="metadata.description" type="string">
      Free-form description of the file.
    </ResponseField>

    <ResponseField name="metadata.summary" type="string">
      Short summary used by agents to decide whether to read the file.
    </ResponseField>

    <ResponseField name="metadata.keywords" type="string[]">
      Searchable keywords associated with the file.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X GET \
    "https://bouncer.nunu.ai/file-storage/my-project?include_metadata=true" \
    -H "X-Api-Key: YOUR_API_TOKEN"
  ```

  ```bash cURL (with agent and test case) theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X GET \
    "https://bouncer.nunu.ai/file-storage/my-project?agent_id=a1b2c3&test_case_id=t1t2t3&include_metadata=true" \
    -H "X-Api-Key: YOUR_API_TOKEN"
  ```

  ```typescript JavaScript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  const projectId = "my-project";
  const params = new URLSearchParams({
    include_metadata: "true",
    agent_id: "a1b2c3",
    test_case_id: "t1t2t3",
  });

  const response = await fetch(
    `https://bouncer.nunu.ai/file-storage/${projectId}?${params}`,
    {
      headers: {
        "X-Api-Key": process.env.NUNU_API_TOKEN,
      },
    }
  );
  const data = await response.json();
  ```

  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import requests
  import os

  project_id = "my-project"

  response = requests.get(
      f"https://bouncer.nunu.ai/file-storage/{project_id}",
      headers={"X-Api-Key": os.environ["NUNU_API_TOKEN"]},
      params={
          "include_metadata": True,
          "agent_id": "a1b2c3",
          "test_case_id": "t1t2t3",
      },
  )
  data = response.json()
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  {
    "projectId": "my-project",
    "count": 3,
    "sections": [
      {
        "scope": "project",
        "count": 2,
        "files": [
          {
            "filename": "game-design.md",
            "path": "game-design.md",
            "size": 4096,
            "uploaded": "2026-04-12T10:30:00.000Z",
            "etag": "9a3b4c5d6e7f8090a1b2c3d4e5f60718",
            "metadata": {
              "description": "High-level design overview",
              "summary": "Mechanics, levels, and progression",
              "keywords": ["design", "gameplay"]
            }
          },
          {
            "filename": "rules.txt",
            "path": "subdir/rules.txt",
            "size": 1234,
            "uploaded": "2026-04-12T10:31:00.000Z",
            "etag": "0a1b2c3d4e5f60718a3b4c5d6e7f8090"
          }
        ]
      },
      {
        "scope": "agent",
        "id": "a1b2c3",
        "count": 1,
        "files": [
          {
            "filename": "agent-prompt.md",
            "path": "agent-prompt.md",
            "size": 512,
            "uploaded": "2026-04-12T10:35:00.000Z",
            "etag": "1b2c3d4e5f60718a3b4c5d6e7f80909a"
          }
        ]
      },
      {
        "scope": "test_case",
        "id": "t1t2t3",
        "count": 0,
        "files": []
      }
    ]
  }
  ```
</ResponseExample>


## OpenAPI

````yaml GET /file-storage/{projectId}
openapi: 3.1.0
info:
  title: nunu.ai API
  description: >-
    The nunu.ai Public API allows you to programmatically interact with your
    projects, manage test runs, and upload builds.
  version: 1.0.0
servers:
  - url: https://nunu.ai/api/v1
security:
  - apiKeyAuth: []
paths:
  /file-storage/{projectId}:
    servers:
      - url: https://bouncer.nunu.ai
        description: Bouncer service (artifact and knowledge delivery)
    get:
      tags:
        - Knowledge
      summary: List Knowledge Files
      description: >-
        List knowledge files for a project. Always returns project-scope files;
        conditionally includes agent- and/or test-case-scope files when their
        IDs are passed as query parameters.
      operationId: listKnowledgeFiles
      parameters:
        - name: projectId
          in: path
          required: true
          description: >-
            The nunu.ai project ID. Must match the project the API key is scoped
            to.
          schema:
            type: string
        - name: agent_id
          in: query
          required: false
          description: Include files from agent/{agent_id}/ in the response.
          schema:
            type: string
        - name: test_case_id
          in: query
          required: false
          description: Include files from test_case/{test_case_id}/ in the response.
          schema:
            type: string
        - name: include_metadata
          in: query
          required: false
          description: >-
            When true, attach parsed metadata (description, summary, keywords)
            for each file from its .{name}.meta.json sidecar.
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListKnowledgeFilesResponse'
        '401':
          description: Unauthorized - missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - API key does not match the requested project
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    ListKnowledgeFilesResponse:
      type: object
      required:
        - projectId
        - count
        - sections
      properties:
        projectId:
          type: string
          description: Echo of the path parameter.
        count:
          type: integer
          description: Total number of files across all included sections.
        sections:
          type: array
          items:
            $ref: '#/components/schemas/KnowledgeFileSection'
          description: >-
            One section per scope returned. The project section is always
            present; other sections only appear when their query param is set.
    Error:
      type: object
      properties:
        error:
          type: string
        code:
          type: string
        details:
          type: object
    KnowledgeFileSection:
      type: object
      required:
        - scope
        - count
        - files
      properties:
        scope:
          type: string
          enum:
            - project
            - agent
            - test_case
          description: Scope of this section.
        id:
          type: string
          description: The agent or test case ID. Omitted for the project section.
        count:
          type: integer
          description: Number of files in this section.
        files:
          type: array
          items:
            $ref: '#/components/schemas/KnowledgeFile'
    KnowledgeFile:
      type: object
      required:
        - filename
        - path
        - size
        - uploaded
        - etag
      properties:
        filename:
          type: string
          description: Basename of the file (no directory prefix).
        path:
          type: string
          description: >-
            Path of the file relative to the scope root (may include
            subdirectories).
        size:
          type: integer
          description: File size in bytes.
        uploaded:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the file was last written.
        etag:
          type: string
          description: Object ETag.
        metadata:
          $ref: '#/components/schemas/KnowledgeFileMetadata'
          description: >-
            Only present when include_metadata=true and a sidecar metadata file
            exists.
    KnowledgeFileMetadata:
      type: object
      description: Parsed metadata from the .{filename}.meta.json sidecar.
      properties:
        description:
          type: string
          description: Free-form description of the file.
        summary:
          type: string
          description: Short summary used by agents to decide whether to read the file.
        keywords:
          type: array
          items:
            type: string
          description: Searchable keywords associated with the file.
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: API key for authentication

````