Agent Native

collections-development

Guides designing and implementing JSON Schema collections for Falcon Foundry apps, including schema definition, CRUD patterns, FQL search syntax, and…

by CrowdStrikeOfficial publisherNot reviewed

Identity proven by GitHub's verified organisation badge (CrowdStrike)

Agents
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode
License
MIT (permissive)
Pin
ec792c5pinned Oct 9, 2026
Context cost
about 4,400 tokenswhen the skill loads
GitHub stars
34on crowdstrike/foundry-skills
Scripts
None found

What it does

“Design JSON Schema collections and CRUD patterns for Falcon Foundry apps. TRIGGER when user asks to "create a collection", "define a JSON schema", "store data in Foundry", runs `foundry collections create`, or needs help with indexable fields, FQL queries, or collection access patterns. DO NOT TRIGGER for workflow YAML, function handlers, or UI components — use the appropriate sub-skill.”
The author's description, from SKILL.md

Generated summary from the skill's own text

Guides designing and implementing JSON Schema collections for Falcon Foundry apps, including schema definition, CRUD patterns, FQL search syntax, and collection exposure to workflows or agents. Covers CLI scaffolding, naming constraints, indexing rules, and common pitfalls in TypeScript and Python.

When to use it

  • Building persistent data stores for Foundry apps with JSON Schema validation
  • Creating searchable collections and implementing FQL query patterns
  • Exposing collections as agent tools or Fusion SOAR workflow actions
  • Writing CRUD code in TypeScript or Python for collection operations

When not to

  • Designing Fusion workflows, YAML manifests, or function handlers separately
  • Storing data with JSON Schema draft 2019-09 or later versions
  • Managing collections through CLI commands instead of API or SDK

Install

These commands install from the publisher's repository and need no account.

skills CLI

npx skills add crowdstrike/foundry-skills --skill collections-development

Installs from the repository's default branch, which may have changed since the commit we checked.

GitHub CLI 2.90 or later

gh skill install crowdstrike/foundry-skills collections-development@ec792c5f4b70efdf73ceceb4adf1bea485513d36

Installs the commit we checked (ec792c5).

Copy by hand

Download the folder at ec792c5 and put it in .claude/skills/collections-development for Claude Code and in .agents/skills/collections-development for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode.

Skill folder on GitHub at ec792c5

Claude Code plugin

/plugin install crowdstrike-falcon-foundry@claude-plugins-official

The publisher's plugin in Claude's official marketplace. It may hold more than this skill, and we have not pinned it.

Claude Code plugin

/plugin install crowdstrike-falcon-fusion@claude-plugins-official

The publisher's plugin in Claude's official marketplace. It may hold more than this skill, and we have not pinned it.

Copy for your agent

A prompt for any coding agent. It installs this skill from GitHub at the pinned commit, copies the files as they are, and runs nothing unless you ask.

Prompt

Install the agent skill "collections-development" by CrowdStrike.

Source, pinned to commit ec792c5f4b70efdf73ceceb4adf1bea485513d36:
https://github.com/crowdstrike/foundry-skills/tree/ec792c5f4b70efdf73ceceb4adf1bea485513d36/skills/collections-development

1. Download that folder at exactly this commit. Do not use the default branch.
2. Copy every file unchanged, keeping the folder structure, into .claude/skills/collections-development/ for Claude Code and .agents/skills/collections-development/ for Codex, Cursor, Gemini CLI, GitHub Copilot and OpenCode. Create the folders if they do not exist.
3. Do not edit the files, and do not run any script in the folder unless I ask you to.
4. When you are done, list the files you copied and where you put them.

Listing and checks: https://www.agentnative.dev/skills/crowdstrike/collections-development

SKILL.md at the pin

---
name: collections-development
description: Design JSON Schema collections and CRUD patterns for Falcon Foundry apps. TRIGGER when user asks to "create a collection", "define a JSON schema", "store data in Foundry", runs `foundry collections create`, or needs help with indexable fields, FQL queries, or collection access patterns. DO NOT TRIGGER for workflow YAML, function handlers, or UI components — use the appropriate sub-skill.
version: 1.6.0
updated: 2026-10-01
tags: [foundry, collections, json-schema, nosql]
author: CrowdStrike
license: MIT
compatibility: Claude Code >=1.0
metadata:
  category: data
---

# Foundry Collections Development

> **Part of a suite.** If `development-workflow` has not already run, and this is a new app or its first capability, load the `development-workflow` skill first — it owns the CLI prerequisite check, scaffolding order, and manifest coordination.

Falcon Foundry Collections are NoSQL document stores with JSON Schema validation. They provide persistent storage for app data with CRUD operations, FQL queries, and schema enforcement.

## Collection Naming Constraints

| Constraint | Rule |
|-----------|------|
| Length | 5-200 characters |
| Start/end | Must begin and end with a letter or number |
| Special characters | Only underscores (`_`) allowed — no hyphens, spaces, or other chars |
| Case | Case-sensitive |

## Collection Description Constraints

| Constraint | Rule |
|-----------|------|
| Length | 3-500 characters |
| Start | Must begin with an alphanumeric character |
| Allowed characters | Letters, numbers, spaces, dashes, periods, parentheses, and underscores only |
| Not allowed | Commas, colons, semicolons, quotes, slashes, or other special characters |

**Check the description against this table before running `collections create`.** The CLI accepts a comma (or any other disallowed character) in `--description` without complaint; the rejection only surfaces later, from `foundry apps validate` or deploy, by which time the collection is already in the manifest and has to be fixed by hand. Write the description with letters, numbers, spaces, dashes, periods, parentheses, and underscores only.

## Collection Limits

| Resource | Limit |
|----------|-------|
| Single object size | ~50 MB |
| Schema size | 256 KB |
| Object key length | 1-1,000 characters |
| Indexed fields per schema | 10 |
| Objects per collection | No enforced limit |
| Collections per app | No enforced limit |
| Search results per page | 500 max (default 50) |

## JSON Schema Requirements

- **JSON Schema draft 7 only** — newer drafts (`draft/2020-12`, `draft/2019-09`) fail validation
- Schema is auto-versioned: v1.0 on creation, auto-incremented on modification
- `additionalProperties: false` recommended — extra fields leak internal data and break type safety
- `x-cs-indexable: true` on individual properties for searchable fields (max 10 per collection)

## CLI Scaffolding

```bash
# Write schema to /tmp/ first — the CLI copies it into collections/
foundry collections create \
  --name "my_collection" \
  --schema /tmp/schema.json \
  --description "App data store" \
  --no-prompt \
  --wf-expose \
  --wf-tags "tag1,tag2"
```

This creates the collection directory, copies the schema, and updates `manifest.yml`. Edit the project copy at `collections/my_collection.json` afterward to refine.

## Exposing a Collection as an Agent Tool

Add `--agent-tools-expose` to let a Foundry AI agent read and write the collection:

```bash
foundry collections create --name "triage_notes" --schema /tmp/schema.json \
  --description "Agent triage notes" --agent-tools-expose --no-prompt
```

That writes one block onto the collection's manifest entry:

```yaml
collections:
    - name: triage_notes
      agent_tools_integration:
        exposed: true
```

Exposure is only half the wiring. The agent must also name each operation it may call in its own `tools` list, using `collections.<collection_name>.<Operation>`:

```yaml
ai:
    agents:
        - name: Detection Triage Agent
          tools:
            - collections.triage_notes.CreateObject
            - collections.triage_notes.SearchObjects
```

Valid operations, exact casing required: `CreateObject`, `GetObject`, `DeleteObject`, `ListObjects`, `SearchObjects`.

A collection exposed but not listed in `tools` is unreachable by the agent, and vice versa — neither case produces an error, just an agent that silently cannot use the data. `agent_tools_integration` is independent of `workflow_integration`; a collection can be exposed to agents, to Fusion, to both, or to neither.

Agents can also use `collections.generic.<Operation>` — a scratch collection the platform creates per agent at runtime, needing no collection of your own. Use a named app collection when the data must outlive the agent or be readable by other capabilities. See `ai-agents-development`.

## Collection API Access

Collections are managed via the CrowdStrike API or the `foundry-js` SDK. There are no CLI commands for reading/writing collection data, and collections can only be deleted from the Falcon Foundry UI (not the CLI).

```
PUT    /customobjects/v1/collections/{collection_name}/objects/{key}  — Create/update object
GET    /customobjects/v1/collections/{collection_name}/objects/{key}  — Get object by key
DELETE /customobjects/v1/collections/{collection_name}/objects/{key}  — Delete object
POST   /customobjects/v1/collections/{collection_name}/objects        — Search objects (FQL filter)
```

## JSON Schema Patterns

### Basic Schema

```json
{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "type": "object",
  "title": "Incident",
  "description": "Security incident record",
  "required": ["id", "title", "severity", "status", "created_at"],
  "additionalProperties": false,
  "properties": {
    "id": { "type": "string", "format": "uuid" },
    "title": { "type": "string", "minLength": 1, "maxLength": 200 },
    "severity": { "type": "integer", "minimum": 1, "maximum": 10 },
    "status": {
      "type": "string",
      "enum": ["open", "investigating", "contained", "resolved", "closed"]
    },
    "tags": {
      "type": "array",
      "items": { "type": "string", "maxLength": 50 },
      "maxItems": 20,
      "uniqueItems": true
    },
    "created_at": { "type": "string", "format": "date-time" }
  }
}
```

### Indexable Fields

Make fields searchable via FQL by marking them indexable. Two patterns are supported:

**Pattern A: Top-level array (preferred — used by most foundry-sample repos)**

```json
{
  "$schema": "https://json-schema.org/draft-07/schema",
  "x-cs-indexable-fields": [
    { "field": "/status", "type": "string", "fql_name": "status" },
    { "field": "/severity", "type": "integer", "fql_name": "severity" },
    { "field": "/created_at", "type": "string", "fql_name": "created_at" }
  ],
  "type": "object",
  "properties": {
    "status": { "type": "string" },
    "severity": { "type": "integer" },
    "created_at": { "type": "string", "format": "date-time" }
  }
}
```

**Pattern B: Per-field annotation**

```json
{
  "properties": {
    "compositeId": { "type": "string", "x-cs-indexable": true },
    "content": { "type": "string" }
  }
}
```

Both patterns work. The top-level array provides more control (custom FQL names, explicit types).

### Manifest Configuration

```yaml
# manifest.yml
collections:
  - name: incidents
    description: Security incident records
    schema: collections/incidents.json
    permissions: []
    workflow_integration:
      system_action: true
      tags:
        - Collection

  - name: audit_logs
    description: Audit log entries
    schema: collections/audit_logs.json
    permissions: []
    workflow_integration:
      system_action: false
      tags: []
```

Indexing is controlled entirely by `x-cs-indexable-fields` or `x-cs-indexable: true` in the JSON schema files, not in the manifest.

## CRUD Operations (TypeScript)

```typescript
import { Collection } from '@crowdstrike/foundry-js';

export class IncidentCollection {
  private collection: Collection<Incident>;

  constructor() {
    this.collection = new Collection<Incident>('incidents');
  }

  async create(data: Omit<Incident, 'id' | 'created_at' | 'updated_at'>): Promise<Incident> {
    const incident: Incident = {
      ...data,
      id: crypto.randomUUID(),
      created_at: new Date().toISOString(),
      updated_at: new Date().toISOString(),
    };
    await this.collection.create(incident.id, incident);
    return incident;
  }

  async get(id: string): Promise<Incident | null> {
    try {
      return await this.collection.get(id);
    } catch (error) {
      if (error.code === 'NOT_FOUND') return null;
      throw error;
    }
  }

  async update(id: string, updates: Partial<Incident>): Promise<Incident> {
    const existing = await this.get(id);
    if (!existing) throw new Error(`Incident ${id} not found`);
    const updated: Incident = {
      ...existing,
      ...updates,
      id: existing.id,
      created_at: existing.created_at,
      updated_at: new Date().toISOString(),
    };
    await this.collection.update(id, updated);
    return updated;
  }

  async delete(id: string): Promise<void> {
    await this.collection.delete(id);
  }

  async list(options?: { status?: string; limit?: number; offset?: number }) {
    const filters: Record<string, any> = {};
    if (options?.status) filters.status = options.status;
    return this.collection.query(filters, {
      limit: options?.limit ?? 50,
      offset: options?.offset ?? 0,
      sort: [{ field: 'created_at', order: 'desc' }],
    });
  }
}
```

## CRUD Operations (Python — from Functions)

Use `CustomStorage` (Service Class) to access collections from Python functions. Service classes are preferred over the Uber class (`APIHarnessV2`) because the Falcon Foundry functions editor auto-detects OAuth scopes from `from falconpy import CustomStorage`. See the `functions-development` skill's `references/python-patterns.md` for a complete handler example with Uber class alternative.

```python
import json
import os
from falconpy import CustomStorage

def _app_headers() -> dict:
    app_id = os.environ.get("APP_ID")
    if app_id:
        return {"X-CS-APP-ID": app_id}
    return {}

# Construct inside the handler in a real function — a module-scope client has no request
# token in Foundry and returns 401 on every call (see functions-development).
client = CustomStorage(ext_headers=_app_headers())

# Create or update (PutObject = upsert). Pass body as a dict.
client.PutObject(collection_name="incidents", object_key="incident-123",
                 body={"id": "incident-123", "title": "Suspicious process", "severity": 7})

# Read — GetObject returns bytes on success, dict on error
response = client.GetObject(collection_name="incidents", object_key="incident-123")
# In production, check isinstance(response, bytes) before decoding — see python-patterns.md for full error handling
incident = json.loads(response.decode("utf-8"))

# Delete
client.DeleteObject(collection_name="incidents", object_key="incident-123")

# Search (FQL filter — only indexed fields)
response = client.SearchObjects(collection_name="incidents",
                                filter="status:'open'+severity:>=5", limit=50)
# SearchObjects returns metadata — follow up with GetObject per key for full objects
for item in response.get("body", {}).get("resources", []):
    obj = client.GetObject(collection_name="incidents", object_key=item["object_key"])
    data = json.loads(obj.decode("utf-8"))

# List every key — ListObjects pages by starting key, not a cursor
keys, start = [], None
while True:
    params = {"start": start} if start else {}
    batch = client.ListObjects(collection_name="incidents", limit=100, **params)["body"].get("resources", [])
    batch = [k for k in batch if k != start]  # drop the start key if it comes back
    if not batch:
        break
    keys.extend(batch)
    start = batch[-1]
```

Key points:
- `CustomStorage(ext_headers=_app_headers())` applies `X-CS-APP-ID` to all requests (needed for local dev; Foundry sets it automatically in production)
- `PutObject` acts as upsert (creates or overwrites by key). Pass body as a dict.
- `GetObject` returns bytes directly — decode with `json.loads(response.decode("utf-8"))`
- **A missing key returns a 404** (see `get_incident` in the `functions-development` skill's `references/python-patterns.md`). Only a 404 means missing; don't treat *every* non-bytes reply that way: a transient 429 or 5xx then reads as "no record", and code that writes the record back erases it.
- `SearchObjects` returns metadata only, not full objects
- `ListObjects` returns keys (alphabetical) in `body.resources` and takes `start`/`end` keys. Pass the last key as the next `start` and stop only on an empty batch — stopping when a page is shorter than `limit` ends early if the service caps page size
- **List before you read.** Calling `GetObject` on every *candidate* key (most of them misses) is slow; list the keys once and read only the ones that exist. In one app, that cut a 519-item page load from about 25 s to about 7 s
- FQL filters only work on fields marked `x-cs-indexable: true` in the collection schema

## FQL Search Syntax

Only fields marked with `x-cs-indexable: true` can be used in FQL queries.

| Operation | Syntax | Example |
|-----------|--------|---------|
| Equality | `field:'value'` | `status:'open'` |
| Numeric comparison | `field:>=N` | `severity:>=5` |
| AND | `field1:'a'+field2:'b'` | `status:'open'+severity:>=5` |
| OR | `field:'a',field:'b'` | `status:'open',status:'investigating'` |
| Wildcard | `field:*'pattern'*` | `title:*'malware'*` |
| Sorting | `sort=field\|asc` | `sort=created_at\|desc` |

The `foundry-js` SDK's `search()` method accepts a `filter` parameter for FQL queries. The search endpoint is `POST /customobjects/v1/collections/{name}/objects` with a `filter` field in the request body.

## Workflow Share Settings

To make a collection accessible from workflows:

```yaml
collections:
  - name: incidents
    schema: collections/incidents/schema.json
    permissions: []
    workflow_integration:
      system_action: true           # true = app workflows only, false = also available as Fusion SOAR action
      tags:
        - Collection
```

| Setting | Behavior |
|---------|----------|
| `workflow_integration.system_action: true` | Available to app workflows only |
| `workflow_integration.system_action: false` | Available to both app workflows AND Falcon Fusion SOAR |

## RBAC and Direct API Access

Collections can be accessed directly via the CrowdStrike API (outside of functions) using custom roles with specific collection permissions. Include the `X-CS-APP-ID` header to identify your Foundry app. Foundry CLI credentials cannot access collections directly; use a separate API client with `Custom Storage` read/write scope.

## Common Pitfalls

- **Using `APIHarnessV2` (Uber class) for collection operations.** Use `CustomStorage` service class instead — the Foundry functions editor auto-detects OAuth scopes from service class imports but cannot parse Uber class `.command()` calls.
- **Using JSON Schema newer than draft 7.** Foundry only supports draft 7.
- **Missing indexes.** Fields used in queries must be marked with `x-cs-indexable: true` or listed in `x-cs-indexable-fields`. Max 10 per collection.
- **Invalid collection names.** Names must be 5-200 chars, start/end with letter or number, and contain only letters, numbers, and underscores.
- **Commas or other punctuation in `--description`.** `collections create` accepts them; `foundry apps validate` and deploy reject them. Stick to letters, numbers, spaces, dashes, periods, parentheses, and underscores.
- **Editing a schema file and redeploying does not change an existing collection.** Writes keep validating against the schema the collection was created with (observed: a new top-level field rejected as `additional properties not allowed` after the schema that declared it was deployed). Ship `"additionalProperties": true` at the top level if fields may be added later, and treat any breaking schema change as a new collection name.
- **Not configuring workflow share settings.** Set `workflow_integration.system_action: true` for app-only workflow access, or `false` to also expose collections as Falcon Fusion SOAR actions.
- **Trying to delete collections via CLI.** Collections can only be deleted from the Falcon Foundry UI.
- **Trying to manage objects via CLI.** Collection CRUD requires the CrowdStrike API or `foundry-js` SDK.
- **Schema field names must match exactly.** If a field name in your write payload doesn't match the collection schema (e.g., writing `score` when the schema defines `severity`), the write fails and returns errors in the response body — but the SDK does not throw. Without checking `result.errors`, the failure is invisible. Always read the collection schema file before writing seed data; verify required fields, enum values, and exact field names.
- **Not checking write responses for errors.** The SDK does not throw on server-side validation failures. Always check `result?.errors?.length` after write operations — errors include specific messages like `"missing property 'severity'"` or `"value must be one of 'low', 'medium', 'high', 'critical'"`. Verify persistence with a follow-up read or list call.

## Reading Guide

| Task | Reference |
|------|-----------|
| Migrations, testing, pagination, extended schemas, counter-rationalizations | [references/advanced-patterns.md](references/advanced-patterns.md) |

## Use Cases

For real-world implementation patterns, see:
- `use-cases/collections.md` — CRUD operations, search, field types
- `use-cases/lookup-table-enrichment.md` — 3rd-party data for automated enrichment

## Reference Implementations

- **[foundry-sample-collections-toolkit](https://github.com/CrowdStrike/foundry-sample-collections-toolkit)**: CSV import, bulk operations, pagination workflows, test data generation. See also [Getting Started with Falcon Foundry Collections](https://www.crowdstrike.com/tech-hub/ng-siem/getting-started-with-falcon-foundry-collections-your-guide-to-structured-data-storage-in-foundry-apps/).

From crowdstrike/foundry-skills at ec792c5, shown as plain text under its license: MIT (permissive). The license text is in skills/collections-development/SKILL.md.

View SKILL.md on GitHub at ec792c5

Files

2 files, 28 KB in total. Each file has a sha256 in the pin's manifest; the first 12 characters are shown.

Skill folder on GitHub at ec792c5
All 19 skills from CrowdStrike

More from CrowdStrike

  • ai-agents-development

    Build and deploy AI agents and knowledge bases in Foundry apps using the CLI.

    Claude Code, Codex, Cursor +3 · about 5.2K tokens · pinned 6 days ago

  • api-integrations

    This skill registers external APIs in Falcon Foundry by downloading the vendor's OpenAPI spec, adapting it for Foundry's requirements, and creating an API…

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 4.8K tokens · pinned 6 days ago

  • debugging-workflows

    This skill provides systematic procedures for diagnosing and fixing Falcon Foundry CLI errors, deployment failures, function execution issues, and development…

    Claude Code, Codex, Cursor +3 · about 4.4K tokens · pinned 6 days ago

  • development-workflow

    Orchestrates the complete Foundry app lifecycle from requirements through scaffolding, building, and deployment.

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 5.1K tokens · pinned 6 days ago

  • e2e-testing

    This skill sets up end-to-end testing for Falcon Foundry applications using Playwright and the @crowdstrike/foundry-playwright library.

    Claude Code, Codex, Cursor +3 · about 5.1K tokens · pinned 6 days ago

  • functions-development

    Equips agents to build, test, and debug serverless Go or Python functions for Falcon Foundry apps.

    Claude Code, Codex, Cursor +3 · about 5.1K tokens · pinned 6 days ago

  • databricks-zerobus-ingest

    This skill enables agents to build gRPC-based data ingestion clients that write records directly into Databricks Delta tables using the Zerobus Ingest SDK.

    by DatabricksOfficial publisher

    Claude Code, Codex, Cursor +4 · about 2.9K tokens · pinned 6 days ago

  • qdrant-advisor

    This skill equips an agent to diagnose and troubleshoot Qdrant vector database deployments by fetching current guidance live from skills.qdrant.tech rather…

    by qdrantCommunity

    Claude Code, Codex, Cursor +4 · about 1.4K tokens · pinned 6 days ago

  • alphagenome-single-variant-analysis

    Analyzes how genetic variants affect gene expression, chromatin accessibility, and splicing using the AlphaGenome API.

    by GoogleOfficial publisher

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 2.8K tokens · pinned 6 days ago

  • alphagenome-variant-impact-score

    Score genetic variants using AlphaGenome Variant Impact models to assess functional impact through 18 biological feature attributions.

    by GoogleOfficial publisher

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 4.1K tokens · pinned 6 days ago

  • chdb-datastore

    This skill enables working with tabular data using a pandas-compatible API backed by ClickHouse for faster execution.

    by ClickHouseOfficial publisher

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 1.2K tokens · pinned 6 days ago

  • chdb-sql

    The skill enables running ClickHouse SQL queries on local files (parquet, csv, json), remote databases (Postgres, MySQL, MongoDB, ClickHouse Cloud), and cloud…

    by ClickHouseOfficial publisher

    Contains scripts

    Claude Code, Codex, Cursor +3 · about 960 tokens · pinned 6 days ago

The skills listed here are third-party software, collected from public GitHub repositories as a catalog of recent skills and provided as is. Agent Native does not write or control them and is not responsible for any harm, loss or damage caused by installing or using them. Labels and checks describe what we saw at one commit and are not a guarantee. Read a skill's files before you run it. Terms of use