{"owner":"OpenCTI-Platform","repo":"opencti","hasSkills":true,"totalSkillsCount":16,"totalTokensCount":9927,"categories":["subagent-persona","copilot-instructions","anthropic-skill","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":[".github/agents/codebase-analyzer.agent.md",".github/copilot-instructions.md",".github/skills/create-playbook-component/SKILL.md",".github/skills/add-feature-flag/SKILL.md",".github/skills/create-react-component/SKILL.md","fds-migration/AGENTS.md",".github/skills/create-workflow/SKILL.md",".github/skills/create-module/SKILL.md",".github/skills/create-creation-form/SKILL.md",".github/skills/create-migration/SKILL.md","AGENTS.md",".github/agents/codebase-locator.agent.md",".github/agents/codebase-pattern-finder.agent.md","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json","opencti-platform/opencti-graphql/src/rules/README.md"],"skills":{".github/agents/codebase-analyzer.agent.md":"---\nname: Codebase Analyzer\ndescription: Analyzes codebase implementation details. Useful when you need to find detailed information about specific components.\nargument-hint: Call it with human language prompt describing what explanation you're looking for.\ntools: [vscode, read, search]\n---\n\nYou are a specialist at understanding HOW code works. \nYour job is to analyze implementation details, trace data flow, and explain technical workings with precise file:line references.\n\nIn user prompt, keywords are in quotes (eg. \"kill chain phases\").\n\n## CRITICAL: YOUR ONLY JOB IS TO DOCUMENT AND EXPLAIN THE CODEBASE AS IT EXISTS TODAY\n\n- DO NOT suggest improvements or changes unless the user explicitly asks for them\n- DO NOT perform root cause analysis unless the user explicitly asks for them\n- DO NOT propose future enhancements unless the user explicitly asks for them\n- DO NOT critique the implementation or identify \"problems\"\n- DO NOT comment on code quality, performance issues, or security concerns\n- DO NOT suggest refactoring, optimization, or better approaches\n- ONLY describe what exists, how it works, and how components interact\n\n## Core Responsibilities\n\n1. **Analyze Implementation Details**\n  - Read specific files to understand logic\n  - Identify key functions and their purposes\n  - Trace method calls and data transformations\n  - Note important algorithms or patterns\n\n2. **Trace Data Flow**\n  - Follow data from entry to exit points\n  - Map transformations and validations\n  - Identify state changes and side effects\n  - Document API contracts between components\n\n3. **Identify Architectural Patterns**\n  - Recognize design patterns in use\n  - Note architectural decisions\n  - Identify conventions and best practices\n  - Find integration points between systems\n\n4. **Identify data Models links**\n  - Identify relationships between related entities\n\n## Analysis Strategy\n\n### Main folders to look into\n\n- `client-python` - API to interact with backend\n- `opencti-worker` - Asynchronous tasks\n- `opencti-platform/opencti-graphql` - Backend\n- `opencti-platform/opencti-front` - Frontend\n- `docs` - Documentation\n\n### Step 1: Read Entry Points\n\n- Start with main files mentioned in the request\n- Look for exports, public methods, or route handlers\n- Identify the \"surface area\" of the component\n\n### Step 2: Follow the Code Path\n\n- Trace function calls step by step\n- Read each file involved in the flow\n- Note where data is transformed\n- Identify external dependencies\n- Take time to ultrathink about how all these pieces connect and interact\n\n### Step 3: Document Key Logic\n\n- Document business logic as it exists\n- Describe validation, transformation, error handling\n- Explain any complex algorithms or calculations\n- Note configuration or feature flags being used\n- DO NOT evaluate if the logic is correct or optimal\n- DO NOT identify potential bugs or issues\n\n## Important Guidelines\n\n- **Always include file:line references** for claims\n- **Read files thoroughly** before making statements\n- **Trace actual code paths** don't assume\n- **Focus on \"how\"** not \"what\" or \"why\"\n- **Be precise** about function names and variables\n- **Note exact transformations** with before/after\n\n## Output Format\n\nUse file paths from root workspace.\nStructure your analysis like this:\n\n```\n## Analysis: [Feature/Component Name]\n\n### Overview\n[2-3 sentence summary of how it works]\n\n### Entry Points\n- `api/routes.js:45` - POST /webhooks endpoint\n- `handlers/webhook.js:12` - handleWebhook() function\n\n### Core Implementation\n\n#### 1. Request Validation (`handlers/webhook.js:15-32`)\n- Validates signature using HMAC-SHA256\n- Checks timestamp to prevent replay attacks\n- Returns 401 if validation fails\n\n#### 2. Data Processing (`services/webhook-processor.js:8-45`)\n- Parses webhook payload at line 10\n- Transforms data structure at line 23\n- Queues for async processing at line 40\n\n#### 3. State Management (`stores/webhook-store.js:55-89`)\n- Stores webhook in database with status 'pending'\n- Updates status after processing\n- Implements retry logic for failures\n\n### Data Flow\n1. Request arrives at `api/routes.js:45`\n2. Routed to `handlers/webhook.js:12`\n3. Validation at `handlers/webhook.js:15-32`\n4. Processing at `services/webhook-processor.js:8`\n5. Storage at `stores/webhook-store.js:55`\n\n### Key Patterns\n- **Factory Pattern**: WebhookProcessor created via factory at `factories/processor.js:20`\n- **Repository Pattern**: Data access abstracted in `stores/webhook-store.js`\n- **Middleware Chain**: Validation middleware at `middleware/auth.js:30`\n\n### Configuration\n- Webhook secret from `config/webhooks.js:5`\n- Retry settings at `config/webhooks.js:12-18`\n- Feature flags checked at `utils/features.js:23`\n\n### Error Handling\n- Validation errors return 401 (`handlers/webhook.js:28`)\n- Processing errors trigger retry (`services/webhook-processor.js:52`)\n- Failed webhooks logged to `logs/webhook-errors.log`\n```\n\n## What NOT to Do\n\n- Don't guess about implementation\n- Don't skip error handling or edge cases\n- Don't ignore configuration or dependencies\n- Don't make architectural recommendations\n- Don't analyze code quality or suggest improvements\n- Don't identify bugs, issues, or potential problems\n- Don't comment on performance or efficiency\n- Don't suggest alternative implementations\n- Don't critique design patterns or architectural choices\n- Don't perform root cause analysis of any issues\n- Don't evaluate security implications\n- Don't recommend best practices or improvements\n\n## REMEMBER: You are a documentarian, not a critic or consultant\n\nYour sole purpose is to explain HOW the code currently works, with surgical precision and exact references. \nYou are creating technical documentation of the existing implementation, NOT performing a code review or consultation.\n\nThink of yourself as a technical writer documenting an existing system for someone who needs to understand it, not as an engineer evaluating or improving it. \nHelp users understand the implementation exactly as it exists today, without any judgment or suggestions for change.",".github/copilot-instructions.md":"# OpenCTI Project Instructions\n\n> **Design system** — before writing or changing any UI, read [`AGENTS.md`](../AGENTS.md)\n> at the repository root. It carries the rule on when the Filigran Design System\n> is mandatory and MUI is not, and names the CI gates that enforce it.\n\n> **Deep-dive references** — read the relevant doc before touching the related code:\n> - [Backend Architecture (opencti-graphql)](instructions/backend.instructions.md)\n> - [Frontend Architecture (opencti-front)](instructions/frontend.instructions.md)\n> - [Python Client & Worker](instructions/python.instructions.md)\n> - [Documentation Authoring (docs)](instructions/docs.instructions.md)\n> - [Code Review Guidelines](instructions/code-review.instructions.md)\n\n> **Copilot Skills** (`.github/skills/`) — procedural playbooks, load the relevant one before starting the task:\n> - `create-module` — Scaffold a new backend domain module (entity type, schema, resolvers, converter)\n> - `create-migration` — Create a new ElasticSearch database migration file\n> - `create-react-component` — Create a new Relay-connected React component\n> - `create-creation-form` — Scaffold a creation form drawer (Formik + Relay mutation)\n> - `create-playbook-component` — Add a new playbook automation component\n> - `create-workflow` — Scaffold a new GitHub Actions workflow\n> - `add-feature-flag` — Put a feature behind a feature flag (constant, attribute `featureFlag`, `@ff`, domain, manager and UI gating) or remove one\n\n## Project Overview\n\nOpenCTI is a cyber threat intelligence platform built with a **monorepo structure** containing:\n- **opencti-platform/opencti-graphql**: Node.js/TypeScript GraphQL API backend\n- **opencti-platform/opencti-front**: React/TypeScript frontend with Relay\n- **client-python**: Python library (pycti) for API access\n- **opencti-worker**: Python worker for background tasks\n- **docs**: MkDocs documentation\n\n## Global Commands & Setup\n\n### 1. Enable Corepack (first-time only)\nOnly needed if Yarn is not already available. Run once per machine:\n```bash\ncorepack enable\n```\nDo **not** add this before every command — assume a dev environment already has corepack enabled.\n\n### 2. Copy .yarnrc.yml (first install only)\nOnly needed when running `yarn install` for the first time in a subdirectory that does not already have `.yarnrc.yml`:\n\n```bash\n# Example for backend\ncd opencti-platform/opencti-graphql\ncp ../.yarnrc.yml .yarnrc.yml\nyarn install\n```\n\nDo **not** copy `.yarnrc.yml` before running tests or other commands — it only matters for `yarn install`.\n\n### 3. Root NX Commands (run from repo root)\nThe root `package.json` uses **NX** to orchestrate all workspaces at once. Prefer these over manually running commands in each subdirectory:\n\n```bash\n# Install all dependencies (frontend + backend + Python)\nyarn deps          # without Python virtualenv\nyarn deps:venv     # with Python virtualenv (recommended)\n\n# Start all dev servers\nyarn dev           # without Python virtualenv\nyarn dev:venv      # with Python virtualenv\n\n# Build everything\nyarn build         # without Python virtualenv\nyarn build:venv    # with Python virtualenv\n\n# Run all tests\nyarn test          # without Python virtualenv\nyarn test:venv     # with Python virtualenv\n\n# Lint everything\nyarn lint\n\n# Regenerate GraphQL schema across all packages\nyarn graphql\n```\n\nThe `:venv` variants wrap the command with a Python virtual environment — use them when working on `client-python` or `opencti-worker` and running the backend app.\n\n### 4. Local Development Stack\nStart the necessary infrastructure (Elastic, Redis, RabbitMQ, Silo):\n```bash\ncd opencti-platform/opencti-dev\ndocker compose up -d\n```\n**(ElasticSearch requires `vm.max_map_count=262144`)**\n\n## Common Pitfalls\n\n- **Yarn install fails**: Is `.yarnrc.yml` present in the subdirectory? Run `cp ../.yarnrc.yml .yarnrc.yml` then retry.\n- **Yarn not found**: Run `corepack enable` once.\n- **Python Dependencies**: Backend requires `yarn install:python`.\n- **Relay**: Frontend requires `yarn relay` after any GraphQL changes.\n- **Node Memory**: Use `NODE_OPTIONS=--max_old_space_size=8192` for large builds.\n\n## Safety Rules\n\n### Destructive Git & File Operations\n**NEVER** run any operation that could cause loss of uncommitted work without explicit user approval. This includes:\n- `git reset --hard`, `git checkout -- <file>`, `git clean -fd`\n- `git stash drop`, `git rebase`, `git push --force`\n- Deleting or overwriting files that may contain unsaved changes\n\n**Before** running any such command:\n1. Run `git status` and `git diff` to identify uncommitted or unstaged changes.\n2. Present a **clear, plain-language summary** of exactly what would be lost (e.g. \"This will discard your unsaved changes to `src/foo.ts` and `src/bar.ts`\").\n3. **Wait for explicit approval** before proceeding.\n\n<!-- filigran-conventions:start -->\n## Commit, PR & issue conventions\n\nAll commits, pull requests and issues in this repository follow the\n[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)\nspecification with a GitHub issue reference:\n\n```\ntype(scope?)!?: description (#issue)\n```\n\n- Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `perf`, `test`,\n  `build`, `ci`, `revert`.\n- The description starts with a lowercase letter and has no trailing period;\n  preserve acronyms and proper nouns.\n- The old `[backend]` / `[frontend]` bracket prefixes are discontinued — use a\n  Conventional Commits scope instead.\n- Pull request titles **must** end with the related issue reference, e.g.\n  `(#1234)`, and every pull request must be linked to an issue.\n- Sign your commits.\n\nWhen generating commit messages, PR titles or issue titles, always follow this\nconvention. See [`.github/LABELS.md`](.github/LABELS.md) for the full title and\nlabel taxonomy.\n<!-- filigran-conventions:end -->\n\n\n<!-- filigran-model-policy:start -->\n## GitHub Copilot model usage\n\nTo keep token consumption under control, pick the model that matches the task:\n\n- **Opus 4.6** — reserve for complex work: deep reasoning, large refactors,\n  architecture design, tricky debugging. It is significantly more\n  token-expensive, so it is not the daily driver.\n- **Sonnet / Gemini / GPT** — default for everyday tasks: autocomplete, small\n  fixes, quick questions, code explanations.\n\nWe have a limited token budget — being mindful of the model you pick makes a\nreal difference at scale. Think of Opus as a specialist you call in when you\nreally need it.\n<!-- filigran-model-policy:end -->\n",".github/skills/create-playbook-component/SKILL.md":"---\nname: create-playbook-component\ndescription: \"Use when: adding a new playbook automation component, implementing a PlaybookComponent interface, or registering a new playbook step\"\n---\n\n# Create Playbook Component\n\n## Prerequisites\n- **Component ID**: Unique uppercase ID (e.g., `PLAYBOOK_MY_COMPONENT`).\n- **Configuration**: List of fields required from the user.\n\n## Procedure\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-graphql/src/modules/playbook/components/<name>-component.ts`.\n\n### Step 2 — Define Configuration Schema\nDefine a TypeScript interface for the config and a JSONSchema for validation.\n\n```typescript\nexport interface MyComponentConfig {\n  key: string;\n}\n\nconst SCHEMA: JSONSchemaType<MyComponentConfig> = {\n  type: 'object',\n  properties: {\n    key: { type: 'string' },\n  },\n  required: ['key'],\n};\n```\n\n### Step 3 — Implement Component Interface\nImplement `PlaybookComponent<MyComponentConfig>`.\n\n```typescript\nexport const PLAYBOOK_MY_COMPONENT: PlaybookComponent<MyComponentConfig> = {\n  id: 'PLAYBOOK_MY_COMPONENT',\n  name: 'My Component',\n  description: 'Does something useful',\n  icon: 'icon-name',\n  is_entry_point: false,\n  is_internal: true,\n  ports: [{ id: 'out', type: 'out' }],\n  configuration_schema: SCHEMA,\n  schema: async () => SCHEMA,\n  executor: async ({ bundle, playbookNode }) => {\n    // Business logic here\n    const config = playbookNode.configuration;\n    \n    return { output_port: 'out', bundle };\n  },\n};\n```\n\n### Step 4 — Register Component\nImport and add to `PLAYBOOK_COMPONENTS` in `src/modules/playbook/playbook-components.ts`.\n",".github/skills/add-feature-flag/SKILL.md":"---\nname: add-feature-flag\ndescription: \"Use when: putting a new or existing feature behind a feature flag (dev feature) in OpenCTI, adding attributes, GraphQL endpoints, managers or UI that must be hidden until a flag is enabled, or removing a feature flag\"\n---\n\n# Add a Feature Flag\n\nFull rules and rationale: [Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n## Prerequisites\n- **Flag name**: UPPER_SNAKE_CASE string (e.g. `MY_FEATURE`) and its constant (`MY_FEATURE_FEATURE_FLAG`).\n- **Scope**: list of new attributes / mappings, GraphQL endpoints, domain entry points and UI screens of the feature.\n\n## Procedure\n\n### Step 1 — Declare the constant\nAdd `export const MY_FEATURE_FEATURE_FLAG = 'MY_FEATURE';` with a one-line comment in\n`opencti-platform/opencti-graphql/src/config/conf.js`, next to the other flags.\n\n### Step 2 — Flag every new attribute definition (DO NOT SKIP)\nFor **each** attribute added by the feature — in a module definition's `attributes`, in\n`src/modules/attributes/*-registrationAttributes.ts`, or as a new entry in the `mappings`\nof an object attribute — add:\n```ts\nfeatureFlag: MY_FEATURE_FEATURE_FLAG,\n```\nWithout it the field is pushed into the ElasticSearch index mapping at startup even when\nthe flag is off, and nothing fails. Re-read every attribute you added before moving on.\n\n### Step 3 — Gate GraphQL endpoints\nAdd `@ff(flags: [\"MY_FEATURE\"])` to every new query, mutation and field\n(`softFail: true` for fields read early by the front end). Run `yarn build:schema`.\n\n### Step 4 — Gate domain logic\n`enforceEnableFeatureFlag(MY_FEATURE_FEATURE_FLAG)` at the start of mutations / entry\npoints; `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)` for conditional branches.\n\n### Step 5 — Gate managers\n- **New manager:** import `ManagerDefinition` and `registerManager` from `src/manager/managerModule.ts`.\n  Import the new manager file for side effects in `src/manager/index.ts`, and register it with\n  `if (isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)) { registerManager(DEFINITION); }`.\n  Gate the registration, never `enabled()` / `enabledToStart()`: a registered manager shows\n  in the platform modules and startup logs even when the flag is off. Keep its own\n  `enabledByConfig` config. Do not add it to `src/managers.ts`.\n- **Existing manager:** leave its registration alone; branch inside the handler with\n  `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)`.\n\nReference: `src/manager/workflowStatusCleanupManager.ts`. Details in the Managers section of\n[Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n### Step 6 — Gate the UI\n`const { isFeatureEnable } = useHelper();` then `isFeatureEnable('MY_FEATURE')` around\nmenus, routes, tabs and form fields. Run `yarn relay` if GraphQL changed.\n\n### Step 7 — Verify\n- `grep -rn \"featureFlag: MY_FEATURE_FEATURE_FLAG\"` lists **every** new attribute and mapping.\n- With fresh test indices, start the platform with the flag disabled: new attributes are absent\n  from the index mapping and attribute registry. GraphQL fields remain in the schema, but\n  flagged resolvers reject access (or return the soft-fail default); the new manager is\n  neither logged at startup nor listed in the platform modules.\n- Start with `APP__ENABLED_DEV_FEATURES='[\"MY_FEATURE\"]'`: the feature works end to end.\n\n## Removing a flag\nDelete the constant, every `featureFlag: MY_FEATURE_FEATURE_FLAG`, every `@ff(...)` and\nevery `enforceEnableFeatureFlag` / `isFeatureEnabled` / `isFeatureEnable` call for it;\nunwrap the `if` around `registerManager`.\nSearch for `MY_FEATURE` in `opencti-graphql` and `opencti-front` and verify that no declarations or guards for this flag remain; retain legitimate feature and manager identifiers.\n",".github/skills/create-react-component/SKILL.md":"---\nname: create-react-component\ndescription: \"Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query\"\n---\n\n# Create React Component (Relay)\n\n## Prerequisites\n- **Parent Component**: Knowing where this will be used.\n- **Fragment**: The data requirements from GraphQL.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing component in `opencti-platform/opencti-front/src/private/components/` that uses `useFragment`. Model the new component after the existing one to stay idiomatic.\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-front/src/private/components/...`.\n\n### Step 2 — Define Fragment & Props\nUse `graphql` tag and `useFragment`.\n\n```tsx\nimport React from 'react';\nimport { graphql, useFragment } from 'react-relay';\nimport { MyComponent_data$key } from './__generated__/MyComponent_data.graphql';\n\nconst myComponentFragment = graphql`\n  fragment MyComponent_data on EntityType {\n    id\n    name\n    description\n  }\n`;\n\ninterface MyComponentProps {\n  data: MyComponent_data$key;\n}\n\nconst MyComponent: React.FC<MyComponentProps> = ({ data }) => {\n  const node = useFragment(myComponentFragment, data);\n\n  return (\n    <div>\n      <h1>{node.name}</h1>\n      <p>{node.description}</p>\n    </div>\n  );\n};\n\nexport default MyComponent;\n```\n\n### Step 3 — Run Relay Compiler\nRun `yarn relay` to generate the TypeScript types.\n","fds-migration/AGENTS.md":"# AGENTS.md — fds-migration (OpenCTI)\n\nGENERATED — do not edit by hand. Regenerate: `pnpm generate:fds-migration --product opencti --write-to-product` (filigran-design-system repo).\n\nThis file is the agent contract for the Filigran Design System migration\nwork in this repo. Read it before touching anything under `fds-migration/`\nor any file listed in `migration-state.json`'s `wiredFiles`.\n\n## Source of truth\n\nTokens, components and their docs live in a separate repo:\n`@filigran/design-system` — the sibling `filigran-design-system/` checkout\nin the Filigran workspace. This repo NEVER defines a design-system token\nlocally: every color, spacing, radius and typography value used here traces\nback to `filigran-design-system/packages/filigran-design-system/src/tokens/theme.css`.\n\nFull machine-readable reference: <https://silver-doodle-mnyv84e.pages.github.io/llms-full.txt>\n(same content as the sibling checkout's `filigran-design-system/llms-full.txt`,\nserved by the docs site).\n\n## Non-negotiable rules\n\n1. **Never hand-edit a generated file.** `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` and its sidecar\n   `.meta.json` are produced by `pnpm generate:mui-bridge` in the\n   filigran-design-system repo. If a value looks wrong, fix `theme.css`\n   upstream (a Figma export, delivered by a human designer) — never patch\n   the generated file here.\n2. **Never invent a token value.** A color/spacing/typography value with no\n   design-system equivalent is a gap to flag (TOKEN-MAPPING.md, section\n   \"Tokens to create in Figma\"), not something to improvise.\n3. **Branch discipline.** All work happens on `fds/*` branches, never on\n   this product's main/master. Run `git branch --show-current` before\n   every commit. No push to any remote without explicit human validation.\n4. **Missing component → flag, never fork.** If a design-system component\n   doesn't exist yet for something you're migrating, report the gap\n   (filigran-design-system's `process/AI-BACKLOG.md` or `ROADMAP.json`)\n   and move on — never build a local approximation.\n5. **The component phase has started — declare every adoption.** Wiring\n   token *values* into the product's MUI theme (IMPLEMENTATION-ROADMAP.md,\n   \"Phase 1\") is no longer the only workstream: products now replace their\n   own container/control components with design-system ones. What changed\n   is not that anything goes — it is that adoptions must be **declared**,\n   not merely written.\n\n   Every adopted component gets an entry in `migration-state.json`'s\n   `libComponentUsage`: the component name, `importFrom`, the exact list\n   of files, the guards it runs under (`imported-from-library`,\n   `no-hardcoded-padding`), and a `reason`. An adoption absent from that\n   list is invisible to `check-fds-conformity.mjs` — it will not be caught\n   when it silently reverts to MUI or when a hardcoded padding creeps back.\n\n   **An agent may convert a component when all four hold:**\n   1. the design-system component **exists** and the capability is verified\n      on the **installed build** (`node_modules`), not on its types, its\n      meta or the changelog;\n   2. the visual delta has been **measured** and either is iso, or is a\n      change a human explicitly asked for — never \"close enough\" chosen\n      silently;\n   3. the conversion loses **no** function, information or interaction —\n      where it would, the site is listed with its reason instead of forced;\n   4. the adoption is **declared** in `libComponentUsage` in the same\n      change set as the code.\n\n   If any of the four fails, stop and report the gap (this repo's\n   `process/AI-BACKLOG.md`) rather than approximate it locally. Rule 4\n   above still applies in full: a missing component is flagged, never\n   forked.\n\n## Where things are\n\n| What | Where |\n|---|---|\n| Generated token data | `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` (+ `.meta.json` sidecar) |\n| Token → theme-field wiring decisions | `fds-migration/TOKEN-MAPPING.md` |\n| What to migrate, in what order, current state | `fds-migration/IMPLEMENTATION-ROADMAP.md` |\n| Session journal (append, never rewrite) | `fds-migration/IMPLEMENTATION-LOG.md` |\n| MUI component → design-system component reference | `fds-migration/COMPONENT-MAPPING.md` |\n| Conformity check (run before every commit touching a wired file) | `node fds-migration/scripts/check-fds-conformity.mjs` |\n| Upstream state manifest | `filigran-design-system/ROADMAP.json` (`implementations`, id `tokens-opencti`) |\n\n## Conformity check\n\nRun `node fds-migration/scripts/check-fds-conformity.mjs` before committing\nany change to a file listed in `migration-state.json`'s `wiredFiles`. It\nverifies the generated bridge file hasn't been hand-edited, that wired\nfiles still import it, and that no hardcoded value has crept back into a\nmigrated zone. Fix everything it reports before committing — it lists\nconcrete file:line issues, it does not need re-deriving by hand.\n\n### Declaring a component-adoption site (`libComponentUsage`)\n\nOnce a real design-system COMPONENT (not just its tokens) is adopted in a\nfile, declare it in `migration-state.json`'s `libComponentUsage` so the\ncheck keeps watching it:\n\n```jsonc\n\"libComponentUsage\": [\n  {\n    \"component\": \"Paper\",\n    \"importFrom\": \"@filigran/design-system\",\n    \"files\": [\"opencti-front/src/.../PanelWidget.tsx\"],\n    \"guards\": [\"imported-from-library\", \"no-hardcoded-padding\"],\n    \"reason\": \"Paper owns padding as a typed prop (0|8|16|24|32) since the Phase 0 round\"\n  }\n]\n```\n\nTwo things to know before writing one:\n\n- **You declare intent, never a pattern.** `guards` names checks the design\n  system implements and maintains; an unknown name is reported `INVALID`\n  rather than passing quietly, so a typo can never read as coverage. Run\n  the check with an obviously wrong name once if you want to see the list.\n- **The scan is structural, not textual.** Each `<Component …>` opening tag\n  is walked to its own closing `>` with quotes, template literals and `{}`\n  nesting tracked, after comments are stripped — so a multiline element is\n  the normal case, a padding on a sibling element is not attributed to this\n  one, and a commented-out class cannot produce a finding. Findings name one\n  element and one line.\n\nAvailable guards today:\n\n| Guard | What it catches |\n|---|---|\n| `imported-from-library` | the component is rendered but no longer imported from the library, or has fallen back to `@mui/material` — a revert the JSX alone cannot show |\n| `no-hardcoded-padding` | a rendered instance sets padding through `className`, `sx` or `style` instead of the component's own `padding` prop, re-forking a scale the component now owns |\n\n## Notes\n\nMUI 6.5 + @mui/styles legacy. Theme files: src/components/ThemeDark.ts / ThemeLight.ts.\n",".github/skills/create-workflow/SKILL.md":"---\nname: create-workflow\ndescription: \"Use when: scaffolding a new GitHub Actions CI/CD workflow, adding automation for tests, builds, releases, or security scans\"\n---\n\n# Create GitHub Action Workflow\n\n## Prerequisites\n- **Workflow Name**: e.g., \"Review Security Scans\"\n- **Trigger**: e.g., `pull_request`, `push`\n- **Job Steps**: e.g., checkout, install deps, run scan\n\n## Procedure\n\n### Step 1 — Create Workflow File\nCreate a new file in `.github/workflows/<workflow-name>.yml`.\n\n```yaml\nname: [Workflow Name]\n\non:\n  [Trigger]:\n    branches: [master]\n\njobs:\n  build:\n    runs-on: ubuntu-26.04\n    steps:\n      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1\n      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v7\n        with:\n          node-version: 20\n          cache: 'yarn'\n      - run: corepack enable\n      - run: yarn install --immutable\n      - name: Run Scan\n        run: [Command]\n```\n\n### Step 2 — Verify Job Dependencies\nEnsure any required secrets or environment variables are available.\n\n### Step 3 — Commit\nCommit with format: `[CI] Add <workflow-name> workflow (#<issue-number>)`\n",".github/skills/create-module/SKILL.md":"---\nname: create-module\ndescription: \"Use when: scaffolding a new backend entity type, domain module, GraphQL schema, resolvers, or STIX converter in opencti-graphql\"\n---\n\n# Create Backend Module\n\n## Prerequisites\n- **Entity Name**: CamelCase (e.g., `MalwareAnalysis`).\n- **Entity Type**: Constant (e.g., `ENTITY_TYPE_MALWARE_ANALYSIS`).\n- **Parent/Category**: e.g., `ABSTRACT_STIX_DOMAIN_OBJECT`.\n\n## Procedure\n\n### Step 1 — Create Directory Structure\nCreate `opencti-platform/opencti-graphql/src/modules/<entityName>`.\n\n### Step 2 — Create Schema File (`<name>.graphql`)\nDefine the Input, Type, Queries, and Mutations.\n\n### Step 3 — Create Type Definition (`<name>-types.ts`)\nDefine TypeScript interfaces for StixObject, StoreEntity, and internal representations.\nExport the `ENTITY_TYPE_X` constant here.\n\n### Step 4 — Create Converter (`<name>-converter.ts`)\nImplement `convert<Name>ToStix` function to map StoreEntity to StixObject.\n\n### Step 5 — Create Domain Logic (`<name>-domain.ts`)\nImplement CRUD functions: `findAll`, `findById`, `add<Name>`, `delete<Name>`.\nUse `listEntities` and `createEntity` from `database/middleware`.\n\n### Step 6 — Create Resolvers (`<name>-resolvers.ts`)\nMap the GraphQL Query/Mutation fields to the functions in `<name>-domain.ts`.\n\n### Step 7 — Create Module Definition (`<name>.ts`)\nImplement `ModuleDefinition` interface.\nDefine attributes, relations, and register the definition using `registerDefinition`.\nIf the module is behind a feature flag, set `featureFlag: <FLAG_CONSTANT>` on **each**\nattribute and nested mapping — see the `add-feature-flag` skill.\n\n### Step 8a — Create GraphQL Registration File (`<name>-graphql.ts`)\nCreate a `<name>-graphql.ts` file in the module folder that imports the module schema/resolvers and calls `registerGraphqlSchema(...)`.\n\n### Step 8b — Register Module in `src/modules/index.ts`\nAdd two distinct imports in `src/modules/index.ts`:\n1. In the **`region registration modules`** section, import `./<entityName>/<entityName>` (module definition registration).\n2. In the **`region graphql registration`** section, import `./<entityName>/<entityName>-graphql` (GraphQL endpoint registration).\n\n### Step 8c — Update GraphQL Unions (if applicable)\nIf the entity belongs to a STIX union type (e.g., `StixObject`, `StixDomainObject`), add it to the relevant unions in `src/schema/opencti.graphql`.\n\n### Step 8d — Regenerate Schema Types\nRun `yarn build:schema` to regenerate TypeScript types from the updated schema.\n",".github/skills/create-creation-form/SKILL.md":"---\nname: create-creation-form\ndescription: \"Use when: scaffolding a creation form drawer with Formik validation and a Relay mutation for a new entity\"\n---\n\n# Create Creation Form (Drawer)\n\n## Prerequisites\n- **Mutation**: GraphQL mutation for creating the entity.\n- **Fields**: List of fields to display.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing creation form in `opencti-platform/opencti-front/src/private/components/` (look for files ending in `Creation.tsx`). Model the new form after the existing one to stay idiomatic.\n\n### Step 1 — Define Mutation & Validation\nUse `Yup` for validation schema.\n\n```tsx\nconst creationMutation = graphql`\n  mutation MyEntityCreationMutation($input: MyEntityAddInput!) {\n    myEntityAdd(input: $input) {\n      ...MyEntityLine_node\n    }\n  }\n`;\n\nconst validationSchema = Yup.object().shape({\n  name: Yup.string().required(t('This field is required')),\n});\n```\n\n### Step 2 — Create Component Structure\nReturn a `Drawer` containing a `Formik` form.\n\n```tsx\nexport const MyEntityCreation: React.FC<Props> = ({ paginationOptions }) => {\n  const [commit] = useApiMutation(creationMutation);\n  \n  const onSubmit = (values, { setSubmitting, resetForm }) => {\n    commit({\n      variables: {\n        input: values,\n      },\n      updater: (store) => {\n        // Use utils/store helper\n        insertNode(store, 'Pagination_myEntities', paginationOptions, 'myEntityAdd');\n      },\n      onCompleted: () => {\n        setSubmitting(false);\n        resetForm();\n      },\n    });\n  };\n\n  return (\n    <Drawer title={t_i18n('Create entity')}>\n      <Formik initialValues={{ name: '' }} validationSchema={validationSchema} onSubmit={onSubmit}>\n         <Form>\n            <Field component={TextField} name=\"name\" label={t_i18n('Name')} />\n             <Button type=\"submit\">{t_i18n('Create')}</Button>\n         </Form>\n      </Formik>\n    </Drawer>\n  );\n};\n```\n",".github/skills/create-migration/SKILL.md":"---\nname: create-migration\ndescription: \"Use when: creating a new ElasticSearch database migration file, adding or transforming data at deploy time\"\n---\n\n# Create Database Migration\n\n## Prerequisites\n- **Description**: Short snake_case description of the change (e.g., `add_description_to_user`).\n\n## Procedure\n\n### Step 1 — Generate Migration File\nUse the current timestamp (ms) as prefix.\nFile: `opencti-platform/opencti-graphql/src/migrations/<timestamp>-<description>.ts`.\n\n### Step 2 — Implement Migration Pattern\nUse the standard template with logging and execution context.\n\n```typescript\nimport { logMigration } from '../config/conf';\n\nconst message = '[MIGRATION] <Description>';\n\nexport const up = async (next: (error?: Error) => void) => {\n  const startTime = Date.now();\n  logMigration.info(`${message} > started`);\n\n  // Implementation here\n  // usage: const context = executionContext('migration');\n  //        await someDomainFunction(context, SYSTEM_USER, args);\n\n  logMigration.info(`${message} > done in ${Date.now() - startTime} ms`);\n  next();\n   };\n\nexport const down = async (next: (error?: Error) => void) => {\n  next();\n};\n```\n","AGENTS.md":"# AGENTS.md — OpenCTI\n\nRepository conventions live in `.github/copilot-instructions.md` and\n`.github/instructions/`. This file covers one thing they do not: the Filigran\nDesign System, which is migrating into this product.\n\n`CLAUDE.md` is a one-line import of this file.\n\n## The priority rule\n\n> If the design system ships the component, using it is mandatory.\n> If the design system does not ship it yet, MUI is the fallback, and the gap\n> must be recorded.\n\nThis paragraph is a copy. The single source is `AGENTS.md` §4 in\n[filigran-design-system](https://github.com/XTM-Foundation/filigran-design-system);\nif the two ever disagree, that one wins.\n\nWhich components are already in service **here** is data, not memory:\n\n```bash\nnode fds-migration/scripts/check-mui-regression.mjs --explain\n```\n\nIt prints what is enforced, what is held while the library settles its API, and\nwhat has no MUI counterpart at all. Record a gap in\n`fds-migration/LIBRARY-FEEDBACK.md`.\n\n## Onboarding — first session in this repo\n\n1. Read this file, then `.github/copilot-instructions.md`.\n2. Touching the front end? Run `--explain` above before writing UI code.\n   Touching the back end? Read `.github/instructions/backend.instructions.md`.\n   Adding or removing a feature flag? Follow `.github/skills/add-feature-flag/SKILL.md` —\n   new attribute definitions need `featureFlag`, not only `@ff` and `isFeatureEnabled`.\n3. Read `fds-migration/AGENTS.md` before changing anything under\n   `fds-migration/` or any file listed in `migration-state.json`'s `wiredFiles`.\n\nWhat will stop you:\n\n| Gate | Fires when |\n|---|---|\n| `check-mui-regression.mjs` | New code imports a MUI component the design system already replaces here |\n| `check-fds-conformity.mjs` | A generated bridge file was hand-edited, went stale, or a hardcoded value returned to a migrated zone |\n\nBoth run in CI on every pull request and go red on a violation. Run them\nlocally first — they name file and line, and never need re-deriving by hand.\nWhether a red one also *prevents* the merge depends on the repository's\nrequired-check settings, which are an administrator's to set.\n\nNever hand-edit a file carrying a `GENERATED` header: fix the source in the\ndesign system repo and regenerate.\n",".github/agents/codebase-locator.agent.md":"# Subagent: codebase-locator.agent\n\nPath: `.github/agents/codebase-locator.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-locator.agent.md)",".github/agents/codebase-pattern-finder.agent.md":"# Subagent: codebase-pattern-finder.agent\n\nPath: `.github/agents/codebase-pattern-finder.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-pattern-finder.agent.md)","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json)","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json)","opencti-platform/opencti-graphql/src/rules/README.md":"# Rules Skill\n\nPath: `opencti-platform/opencti-graphql/src/rules/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-graphql/src/rules/README.md)"},"files":{".github/agents/codebase-analyzer.agent.md":"---\nname: Codebase Analyzer\ndescription: Analyzes codebase implementation details. Useful when you need to find detailed information about specific components.\nargument-hint: Call it with human language prompt describing what explanation you're looking for.\ntools: [vscode, read, search]\n---\n\nYou are a specialist at understanding HOW code works. \nYour job is to analyze implementation details, trace data flow, and explain technical workings with precise file:line references.\n\nIn user prompt, keywords are in quotes (eg. \"kill chain phases\").\n\n## CRITICAL: YOUR ONLY JOB IS TO DOCUMENT AND EXPLAIN THE CODEBASE AS IT EXISTS TODAY\n\n- DO NOT suggest improvements or changes unless the user explicitly asks for them\n- DO NOT perform root cause analysis unless the user explicitly asks for them\n- DO NOT propose future enhancements unless the user explicitly asks for them\n- DO NOT critique the implementation or identify \"problems\"\n- DO NOT comment on code quality, performance issues, or security concerns\n- DO NOT suggest refactoring, optimization, or better approaches\n- ONLY describe what exists, how it works, and how components interact\n\n## Core Responsibilities\n\n1. **Analyze Implementation Details**\n  - Read specific files to understand logic\n  - Identify key functions and their purposes\n  - Trace method calls and data transformations\n  - Note important algorithms or patterns\n\n2. **Trace Data Flow**\n  - Follow data from entry to exit points\n  - Map transformations and validations\n  - Identify state changes and side effects\n  - Document API contracts between components\n\n3. **Identify Architectural Patterns**\n  - Recognize design patterns in use\n  - Note architectural decisions\n  - Identify conventions and best practices\n  - Find integration points between systems\n\n4. **Identify data Models links**\n  - Identify relationships between related entities\n\n## Analysis Strategy\n\n### Main folders to look into\n\n- `client-python` - API to interact with backend\n- `opencti-worker` - Asynchronous tasks\n- `opencti-platform/opencti-graphql` - Backend\n- `opencti-platform/opencti-front` - Frontend\n- `docs` - Documentation\n\n### Step 1: Read Entry Points\n\n- Start with main files mentioned in the request\n- Look for exports, public methods, or route handlers\n- Identify the \"surface area\" of the component\n\n### Step 2: Follow the Code Path\n\n- Trace function calls step by step\n- Read each file involved in the flow\n- Note where data is transformed\n- Identify external dependencies\n- Take time to ultrathink about how all these pieces connect and interact\n\n### Step 3: Document Key Logic\n\n- Document business logic as it exists\n- Describe validation, transformation, error handling\n- Explain any complex algorithms or calculations\n- Note configuration or feature flags being used\n- DO NOT evaluate if the logic is correct or optimal\n- DO NOT identify potential bugs or issues\n\n## Important Guidelines\n\n- **Always include file:line references** for claims\n- **Read files thoroughly** before making statements\n- **Trace actual code paths** don't assume\n- **Focus on \"how\"** not \"what\" or \"why\"\n- **Be precise** about function names and variables\n- **Note exact transformations** with before/after\n\n## Output Format\n\nUse file paths from root workspace.\nStructure your analysis like this:\n\n```\n## Analysis: [Feature/Component Name]\n\n### Overview\n[2-3 sentence summary of how it works]\n\n### Entry Points\n- `api/routes.js:45` - POST /webhooks endpoint\n- `handlers/webhook.js:12` - handleWebhook() function\n\n### Core Implementation\n\n#### 1. Request Validation (`handlers/webhook.js:15-32`)\n- Validates signature using HMAC-SHA256\n- Checks timestamp to prevent replay attacks\n- Returns 401 if validation fails\n\n#### 2. Data Processing (`services/webhook-processor.js:8-45`)\n- Parses webhook payload at line 10\n- Transforms data structure at line 23\n- Queues for async processing at line 40\n\n#### 3. State Management (`stores/webhook-store.js:55-89`)\n- Stores webhook in database with status 'pending'\n- Updates status after processing\n- Implements retry logic for failures\n\n### Data Flow\n1. Request arrives at `api/routes.js:45`\n2. Routed to `handlers/webhook.js:12`\n3. Validation at `handlers/webhook.js:15-32`\n4. Processing at `services/webhook-processor.js:8`\n5. Storage at `stores/webhook-store.js:55`\n\n### Key Patterns\n- **Factory Pattern**: WebhookProcessor created via factory at `factories/processor.js:20`\n- **Repository Pattern**: Data access abstracted in `stores/webhook-store.js`\n- **Middleware Chain**: Validation middleware at `middleware/auth.js:30`\n\n### Configuration\n- Webhook secret from `config/webhooks.js:5`\n- Retry settings at `config/webhooks.js:12-18`\n- Feature flags checked at `utils/features.js:23`\n\n### Error Handling\n- Validation errors return 401 (`handlers/webhook.js:28`)\n- Processing errors trigger retry (`services/webhook-processor.js:52`)\n- Failed webhooks logged to `logs/webhook-errors.log`\n```\n\n## What NOT to Do\n\n- Don't guess about implementation\n- Don't skip error handling or edge cases\n- Don't ignore configuration or dependencies\n- Don't make architectural recommendations\n- Don't analyze code quality or suggest improvements\n- Don't identify bugs, issues, or potential problems\n- Don't comment on performance or efficiency\n- Don't suggest alternative implementations\n- Don't critique design patterns or architectural choices\n- Don't perform root cause analysis of any issues\n- Don't evaluate security implications\n- Don't recommend best practices or improvements\n\n## REMEMBER: You are a documentarian, not a critic or consultant\n\nYour sole purpose is to explain HOW the code currently works, with surgical precision and exact references. \nYou are creating technical documentation of the existing implementation, NOT performing a code review or consultation.\n\nThink of yourself as a technical writer documenting an existing system for someone who needs to understand it, not as an engineer evaluating or improving it. \nHelp users understand the implementation exactly as it exists today, without any judgment or suggestions for change.",".github/copilot-instructions.md":"# OpenCTI Project Instructions\n\n> **Design system** — before writing or changing any UI, read [`AGENTS.md`](../AGENTS.md)\n> at the repository root. It carries the rule on when the Filigran Design System\n> is mandatory and MUI is not, and names the CI gates that enforce it.\n\n> **Deep-dive references** — read the relevant doc before touching the related code:\n> - [Backend Architecture (opencti-graphql)](instructions/backend.instructions.md)\n> - [Frontend Architecture (opencti-front)](instructions/frontend.instructions.md)\n> - [Python Client & Worker](instructions/python.instructions.md)\n> - [Documentation Authoring (docs)](instructions/docs.instructions.md)\n> - [Code Review Guidelines](instructions/code-review.instructions.md)\n\n> **Copilot Skills** (`.github/skills/`) — procedural playbooks, load the relevant one before starting the task:\n> - `create-module` — Scaffold a new backend domain module (entity type, schema, resolvers, converter)\n> - `create-migration` — Create a new ElasticSearch database migration file\n> - `create-react-component` — Create a new Relay-connected React component\n> - `create-creation-form` — Scaffold a creation form drawer (Formik + Relay mutation)\n> - `create-playbook-component` — Add a new playbook automation component\n> - `create-workflow` — Scaffold a new GitHub Actions workflow\n> - `add-feature-flag` — Put a feature behind a feature flag (constant, attribute `featureFlag`, `@ff`, domain, manager and UI gating) or remove one\n\n## Project Overview\n\nOpenCTI is a cyber threat intelligence platform built with a **monorepo structure** containing:\n- **opencti-platform/opencti-graphql**: Node.js/TypeScript GraphQL API backend\n- **opencti-platform/opencti-front**: React/TypeScript frontend with Relay\n- **client-python**: Python library (pycti) for API access\n- **opencti-worker**: Python worker for background tasks\n- **docs**: MkDocs documentation\n\n## Global Commands & Setup\n\n### 1. Enable Corepack (first-time only)\nOnly needed if Yarn is not already available. Run once per machine:\n```bash\ncorepack enable\n```\nDo **not** add this before every command — assume a dev environment already has corepack enabled.\n\n### 2. Copy .yarnrc.yml (first install only)\nOnly needed when running `yarn install` for the first time in a subdirectory that does not already have `.yarnrc.yml`:\n\n```bash\n# Example for backend\ncd opencti-platform/opencti-graphql\ncp ../.yarnrc.yml .yarnrc.yml\nyarn install\n```\n\nDo **not** copy `.yarnrc.yml` before running tests or other commands — it only matters for `yarn install`.\n\n### 3. Root NX Commands (run from repo root)\nThe root `package.json` uses **NX** to orchestrate all workspaces at once. Prefer these over manually running commands in each subdirectory:\n\n```bash\n# Install all dependencies (frontend + backend + Python)\nyarn deps          # without Python virtualenv\nyarn deps:venv     # with Python virtualenv (recommended)\n\n# Start all dev servers\nyarn dev           # without Python virtualenv\nyarn dev:venv      # with Python virtualenv\n\n# Build everything\nyarn build         # without Python virtualenv\nyarn build:venv    # with Python virtualenv\n\n# Run all tests\nyarn test          # without Python virtualenv\nyarn test:venv     # with Python virtualenv\n\n# Lint everything\nyarn lint\n\n# Regenerate GraphQL schema across all packages\nyarn graphql\n```\n\nThe `:venv` variants wrap the command with a Python virtual environment — use them when working on `client-python` or `opencti-worker` and running the backend app.\n\n### 4. Local Development Stack\nStart the necessary infrastructure (Elastic, Redis, RabbitMQ, Silo):\n```bash\ncd opencti-platform/opencti-dev\ndocker compose up -d\n```\n**(ElasticSearch requires `vm.max_map_count=262144`)**\n\n## Common Pitfalls\n\n- **Yarn install fails**: Is `.yarnrc.yml` present in the subdirectory? Run `cp ../.yarnrc.yml .yarnrc.yml` then retry.\n- **Yarn not found**: Run `corepack enable` once.\n- **Python Dependencies**: Backend requires `yarn install:python`.\n- **Relay**: Frontend requires `yarn relay` after any GraphQL changes.\n- **Node Memory**: Use `NODE_OPTIONS=--max_old_space_size=8192` for large builds.\n\n## Safety Rules\n\n### Destructive Git & File Operations\n**NEVER** run any operation that could cause loss of uncommitted work without explicit user approval. This includes:\n- `git reset --hard`, `git checkout -- <file>`, `git clean -fd`\n- `git stash drop`, `git rebase`, `git push --force`\n- Deleting or overwriting files that may contain unsaved changes\n\n**Before** running any such command:\n1. Run `git status` and `git diff` to identify uncommitted or unstaged changes.\n2. Present a **clear, plain-language summary** of exactly what would be lost (e.g. \"This will discard your unsaved changes to `src/foo.ts` and `src/bar.ts`\").\n3. **Wait for explicit approval** before proceeding.\n\n<!-- filigran-conventions:start -->\n## Commit, PR & issue conventions\n\nAll commits, pull requests and issues in this repository follow the\n[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)\nspecification with a GitHub issue reference:\n\n```\ntype(scope?)!?: description (#issue)\n```\n\n- Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `perf`, `test`,\n  `build`, `ci`, `revert`.\n- The description starts with a lowercase letter and has no trailing period;\n  preserve acronyms and proper nouns.\n- The old `[backend]` / `[frontend]` bracket prefixes are discontinued — use a\n  Conventional Commits scope instead.\n- Pull request titles **must** end with the related issue reference, e.g.\n  `(#1234)`, and every pull request must be linked to an issue.\n- Sign your commits.\n\nWhen generating commit messages, PR titles or issue titles, always follow this\nconvention. See [`.github/LABELS.md`](.github/LABELS.md) for the full title and\nlabel taxonomy.\n<!-- filigran-conventions:end -->\n\n\n<!-- filigran-model-policy:start -->\n## GitHub Copilot model usage\n\nTo keep token consumption under control, pick the model that matches the task:\n\n- **Opus 4.6** — reserve for complex work: deep reasoning, large refactors,\n  architecture design, tricky debugging. It is significantly more\n  token-expensive, so it is not the daily driver.\n- **Sonnet / Gemini / GPT** — default for everyday tasks: autocomplete, small\n  fixes, quick questions, code explanations.\n\nWe have a limited token budget — being mindful of the model you pick makes a\nreal difference at scale. Think of Opus as a specialist you call in when you\nreally need it.\n<!-- filigran-model-policy:end -->\n",".github/skills/create-playbook-component/SKILL.md":"---\nname: create-playbook-component\ndescription: \"Use when: adding a new playbook automation component, implementing a PlaybookComponent interface, or registering a new playbook step\"\n---\n\n# Create Playbook Component\n\n## Prerequisites\n- **Component ID**: Unique uppercase ID (e.g., `PLAYBOOK_MY_COMPONENT`).\n- **Configuration**: List of fields required from the user.\n\n## Procedure\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-graphql/src/modules/playbook/components/<name>-component.ts`.\n\n### Step 2 — Define Configuration Schema\nDefine a TypeScript interface for the config and a JSONSchema for validation.\n\n```typescript\nexport interface MyComponentConfig {\n  key: string;\n}\n\nconst SCHEMA: JSONSchemaType<MyComponentConfig> = {\n  type: 'object',\n  properties: {\n    key: { type: 'string' },\n  },\n  required: ['key'],\n};\n```\n\n### Step 3 — Implement Component Interface\nImplement `PlaybookComponent<MyComponentConfig>`.\n\n```typescript\nexport const PLAYBOOK_MY_COMPONENT: PlaybookComponent<MyComponentConfig> = {\n  id: 'PLAYBOOK_MY_COMPONENT',\n  name: 'My Component',\n  description: 'Does something useful',\n  icon: 'icon-name',\n  is_entry_point: false,\n  is_internal: true,\n  ports: [{ id: 'out', type: 'out' }],\n  configuration_schema: SCHEMA,\n  schema: async () => SCHEMA,\n  executor: async ({ bundle, playbookNode }) => {\n    // Business logic here\n    const config = playbookNode.configuration;\n    \n    return { output_port: 'out', bundle };\n  },\n};\n```\n\n### Step 4 — Register Component\nImport and add to `PLAYBOOK_COMPONENTS` in `src/modules/playbook/playbook-components.ts`.\n",".github/skills/add-feature-flag/SKILL.md":"---\nname: add-feature-flag\ndescription: \"Use when: putting a new or existing feature behind a feature flag (dev feature) in OpenCTI, adding attributes, GraphQL endpoints, managers or UI that must be hidden until a flag is enabled, or removing a feature flag\"\n---\n\n# Add a Feature Flag\n\nFull rules and rationale: [Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n## Prerequisites\n- **Flag name**: UPPER_SNAKE_CASE string (e.g. `MY_FEATURE`) and its constant (`MY_FEATURE_FEATURE_FLAG`).\n- **Scope**: list of new attributes / mappings, GraphQL endpoints, domain entry points and UI screens of the feature.\n\n## Procedure\n\n### Step 1 — Declare the constant\nAdd `export const MY_FEATURE_FEATURE_FLAG = 'MY_FEATURE';` with a one-line comment in\n`opencti-platform/opencti-graphql/src/config/conf.js`, next to the other flags.\n\n### Step 2 — Flag every new attribute definition (DO NOT SKIP)\nFor **each** attribute added by the feature — in a module definition's `attributes`, in\n`src/modules/attributes/*-registrationAttributes.ts`, or as a new entry in the `mappings`\nof an object attribute — add:\n```ts\nfeatureFlag: MY_FEATURE_FEATURE_FLAG,\n```\nWithout it the field is pushed into the ElasticSearch index mapping at startup even when\nthe flag is off, and nothing fails. Re-read every attribute you added before moving on.\n\n### Step 3 — Gate GraphQL endpoints\nAdd `@ff(flags: [\"MY_FEATURE\"])` to every new query, mutation and field\n(`softFail: true` for fields read early by the front end). Run `yarn build:schema`.\n\n### Step 4 — Gate domain logic\n`enforceEnableFeatureFlag(MY_FEATURE_FEATURE_FLAG)` at the start of mutations / entry\npoints; `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)` for conditional branches.\n\n### Step 5 — Gate managers\n- **New manager:** import `ManagerDefinition` and `registerManager` from `src/manager/managerModule.ts`.\n  Import the new manager file for side effects in `src/manager/index.ts`, and register it with\n  `if (isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)) { registerManager(DEFINITION); }`.\n  Gate the registration, never `enabled()` / `enabledToStart()`: a registered manager shows\n  in the platform modules and startup logs even when the flag is off. Keep its own\n  `enabledByConfig` config. Do not add it to `src/managers.ts`.\n- **Existing manager:** leave its registration alone; branch inside the handler with\n  `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)`.\n\nReference: `src/manager/workflowStatusCleanupManager.ts`. Details in the Managers section of\n[Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n### Step 6 — Gate the UI\n`const { isFeatureEnable } = useHelper();` then `isFeatureEnable('MY_FEATURE')` around\nmenus, routes, tabs and form fields. Run `yarn relay` if GraphQL changed.\n\n### Step 7 — Verify\n- `grep -rn \"featureFlag: MY_FEATURE_FEATURE_FLAG\"` lists **every** new attribute and mapping.\n- With fresh test indices, start the platform with the flag disabled: new attributes are absent\n  from the index mapping and attribute registry. GraphQL fields remain in the schema, but\n  flagged resolvers reject access (or return the soft-fail default); the new manager is\n  neither logged at startup nor listed in the platform modules.\n- Start with `APP__ENABLED_DEV_FEATURES='[\"MY_FEATURE\"]'`: the feature works end to end.\n\n## Removing a flag\nDelete the constant, every `featureFlag: MY_FEATURE_FEATURE_FLAG`, every `@ff(...)` and\nevery `enforceEnableFeatureFlag` / `isFeatureEnabled` / `isFeatureEnable` call for it;\nunwrap the `if` around `registerManager`.\nSearch for `MY_FEATURE` in `opencti-graphql` and `opencti-front` and verify that no declarations or guards for this flag remain; retain legitimate feature and manager identifiers.\n",".github/skills/create-react-component/SKILL.md":"---\nname: create-react-component\ndescription: \"Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query\"\n---\n\n# Create React Component (Relay)\n\n## Prerequisites\n- **Parent Component**: Knowing where this will be used.\n- **Fragment**: The data requirements from GraphQL.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing component in `opencti-platform/opencti-front/src/private/components/` that uses `useFragment`. Model the new component after the existing one to stay idiomatic.\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-front/src/private/components/...`.\n\n### Step 2 — Define Fragment & Props\nUse `graphql` tag and `useFragment`.\n\n```tsx\nimport React from 'react';\nimport { graphql, useFragment } from 'react-relay';\nimport { MyComponent_data$key } from './__generated__/MyComponent_data.graphql';\n\nconst myComponentFragment = graphql`\n  fragment MyComponent_data on EntityType {\n    id\n    name\n    description\n  }\n`;\n\ninterface MyComponentProps {\n  data: MyComponent_data$key;\n}\n\nconst MyComponent: React.FC<MyComponentProps> = ({ data }) => {\n  const node = useFragment(myComponentFragment, data);\n\n  return (\n    <div>\n      <h1>{node.name}</h1>\n      <p>{node.description}</p>\n    </div>\n  );\n};\n\nexport default MyComponent;\n```\n\n### Step 3 — Run Relay Compiler\nRun `yarn relay` to generate the TypeScript types.\n","fds-migration/AGENTS.md":"# AGENTS.md — fds-migration (OpenCTI)\n\nGENERATED — do not edit by hand. Regenerate: `pnpm generate:fds-migration --product opencti --write-to-product` (filigran-design-system repo).\n\nThis file is the agent contract for the Filigran Design System migration\nwork in this repo. Read it before touching anything under `fds-migration/`\nor any file listed in `migration-state.json`'s `wiredFiles`.\n\n## Source of truth\n\nTokens, components and their docs live in a separate repo:\n`@filigran/design-system` — the sibling `filigran-design-system/` checkout\nin the Filigran workspace. This repo NEVER defines a design-system token\nlocally: every color, spacing, radius and typography value used here traces\nback to `filigran-design-system/packages/filigran-design-system/src/tokens/theme.css`.\n\nFull machine-readable reference: <https://silver-doodle-mnyv84e.pages.github.io/llms-full.txt>\n(same content as the sibling checkout's `filigran-design-system/llms-full.txt`,\nserved by the docs site).\n\n## Non-negotiable rules\n\n1. **Never hand-edit a generated file.** `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` and its sidecar\n   `.meta.json` are produced by `pnpm generate:mui-bridge` in the\n   filigran-design-system repo. If a value looks wrong, fix `theme.css`\n   upstream (a Figma export, delivered by a human designer) — never patch\n   the generated file here.\n2. **Never invent a token value.** A color/spacing/typography value with no\n   design-system equivalent is a gap to flag (TOKEN-MAPPING.md, section\n   \"Tokens to create in Figma\"), not something to improvise.\n3. **Branch discipline.** All work happens on `fds/*` branches, never on\n   this product's main/master. Run `git branch --show-current` before\n   every commit. No push to any remote without explicit human validation.\n4. **Missing component → flag, never fork.** If a design-system component\n   doesn't exist yet for something you're migrating, report the gap\n   (filigran-design-system's `process/AI-BACKLOG.md` or `ROADMAP.json`)\n   and move on — never build a local approximation.\n5. **The component phase has started — declare every adoption.** Wiring\n   token *values* into the product's MUI theme (IMPLEMENTATION-ROADMAP.md,\n   \"Phase 1\") is no longer the only workstream: products now replace their\n   own container/control components with design-system ones. What changed\n   is not that anything goes — it is that adoptions must be **declared**,\n   not merely written.\n\n   Every adopted component gets an entry in `migration-state.json`'s\n   `libComponentUsage`: the component name, `importFrom`, the exact list\n   of files, the guards it runs under (`imported-from-library`,\n   `no-hardcoded-padding`), and a `reason`. An adoption absent from that\n   list is invisible to `check-fds-conformity.mjs` — it will not be caught\n   when it silently reverts to MUI or when a hardcoded padding creeps back.\n\n   **An agent may convert a component when all four hold:**\n   1. the design-system component **exists** and the capability is verified\n      on the **installed build** (`node_modules`), not on its types, its\n      meta or the changelog;\n   2. the visual delta has been **measured** and either is iso, or is a\n      change a human explicitly asked for — never \"close enough\" chosen\n      silently;\n   3. the conversion loses **no** function, information or interaction —\n      where it would, the site is listed with its reason instead of forced;\n   4. the adoption is **declared** in `libComponentUsage` in the same\n      change set as the code.\n\n   If any of the four fails, stop and report the gap (this repo's\n   `process/AI-BACKLOG.md`) rather than approximate it locally. Rule 4\n   above still applies in full: a missing component is flagged, never\n   forked.\n\n## Where things are\n\n| What | Where |\n|---|---|\n| Generated token data | `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` (+ `.meta.json` sidecar) |\n| Token → theme-field wiring decisions | `fds-migration/TOKEN-MAPPING.md` |\n| What to migrate, in what order, current state | `fds-migration/IMPLEMENTATION-ROADMAP.md` |\n| Session journal (append, never rewrite) | `fds-migration/IMPLEMENTATION-LOG.md` |\n| MUI component → design-system component reference | `fds-migration/COMPONENT-MAPPING.md` |\n| Conformity check (run before every commit touching a wired file) | `node fds-migration/scripts/check-fds-conformity.mjs` |\n| Upstream state manifest | `filigran-design-system/ROADMAP.json` (`implementations`, id `tokens-opencti`) |\n\n## Conformity check\n\nRun `node fds-migration/scripts/check-fds-conformity.mjs` before committing\nany change to a file listed in `migration-state.json`'s `wiredFiles`. It\nverifies the generated bridge file hasn't been hand-edited, that wired\nfiles still import it, and that no hardcoded value has crept back into a\nmigrated zone. Fix everything it reports before committing — it lists\nconcrete file:line issues, it does not need re-deriving by hand.\n\n### Declaring a component-adoption site (`libComponentUsage`)\n\nOnce a real design-system COMPONENT (not just its tokens) is adopted in a\nfile, declare it in `migration-state.json`'s `libComponentUsage` so the\ncheck keeps watching it:\n\n```jsonc\n\"libComponentUsage\": [\n  {\n    \"component\": \"Paper\",\n    \"importFrom\": \"@filigran/design-system\",\n    \"files\": [\"opencti-front/src/.../PanelWidget.tsx\"],\n    \"guards\": [\"imported-from-library\", \"no-hardcoded-padding\"],\n    \"reason\": \"Paper owns padding as a typed prop (0|8|16|24|32) since the Phase 0 round\"\n  }\n]\n```\n\nTwo things to know before writing one:\n\n- **You declare intent, never a pattern.** `guards` names checks the design\n  system implements and maintains; an unknown name is reported `INVALID`\n  rather than passing quietly, so a typo can never read as coverage. Run\n  the check with an obviously wrong name once if you want to see the list.\n- **The scan is structural, not textual.** Each `<Component …>` opening tag\n  is walked to its own closing `>` with quotes, template literals and `{}`\n  nesting tracked, after comments are stripped — so a multiline element is\n  the normal case, a padding on a sibling element is not attributed to this\n  one, and a commented-out class cannot produce a finding. Findings name one\n  element and one line.\n\nAvailable guards today:\n\n| Guard | What it catches |\n|---|---|\n| `imported-from-library` | the component is rendered but no longer imported from the library, or has fallen back to `@mui/material` — a revert the JSX alone cannot show |\n| `no-hardcoded-padding` | a rendered instance sets padding through `className`, `sx` or `style` instead of the component's own `padding` prop, re-forking a scale the component now owns |\n\n## Notes\n\nMUI 6.5 + @mui/styles legacy. Theme files: src/components/ThemeDark.ts / ThemeLight.ts.\n",".github/skills/create-workflow/SKILL.md":"---\nname: create-workflow\ndescription: \"Use when: scaffolding a new GitHub Actions CI/CD workflow, adding automation for tests, builds, releases, or security scans\"\n---\n\n# Create GitHub Action Workflow\n\n## Prerequisites\n- **Workflow Name**: e.g., \"Review Security Scans\"\n- **Trigger**: e.g., `pull_request`, `push`\n- **Job Steps**: e.g., checkout, install deps, run scan\n\n## Procedure\n\n### Step 1 — Create Workflow File\nCreate a new file in `.github/workflows/<workflow-name>.yml`.\n\n```yaml\nname: [Workflow Name]\n\non:\n  [Trigger]:\n    branches: [master]\n\njobs:\n  build:\n    runs-on: ubuntu-26.04\n    steps:\n      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1\n      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v7\n        with:\n          node-version: 20\n          cache: 'yarn'\n      - run: corepack enable\n      - run: yarn install --immutable\n      - name: Run Scan\n        run: [Command]\n```\n\n### Step 2 — Verify Job Dependencies\nEnsure any required secrets or environment variables are available.\n\n### Step 3 — Commit\nCommit with format: `[CI] Add <workflow-name> workflow (#<issue-number>)`\n",".github/skills/create-module/SKILL.md":"---\nname: create-module\ndescription: \"Use when: scaffolding a new backend entity type, domain module, GraphQL schema, resolvers, or STIX converter in opencti-graphql\"\n---\n\n# Create Backend Module\n\n## Prerequisites\n- **Entity Name**: CamelCase (e.g., `MalwareAnalysis`).\n- **Entity Type**: Constant (e.g., `ENTITY_TYPE_MALWARE_ANALYSIS`).\n- **Parent/Category**: e.g., `ABSTRACT_STIX_DOMAIN_OBJECT`.\n\n## Procedure\n\n### Step 1 — Create Directory Structure\nCreate `opencti-platform/opencti-graphql/src/modules/<entityName>`.\n\n### Step 2 — Create Schema File (`<name>.graphql`)\nDefine the Input, Type, Queries, and Mutations.\n\n### Step 3 — Create Type Definition (`<name>-types.ts`)\nDefine TypeScript interfaces for StixObject, StoreEntity, and internal representations.\nExport the `ENTITY_TYPE_X` constant here.\n\n### Step 4 — Create Converter (`<name>-converter.ts`)\nImplement `convert<Name>ToStix` function to map StoreEntity to StixObject.\n\n### Step 5 — Create Domain Logic (`<name>-domain.ts`)\nImplement CRUD functions: `findAll`, `findById`, `add<Name>`, `delete<Name>`.\nUse `listEntities` and `createEntity` from `database/middleware`.\n\n### Step 6 — Create Resolvers (`<name>-resolvers.ts`)\nMap the GraphQL Query/Mutation fields to the functions in `<name>-domain.ts`.\n\n### Step 7 — Create Module Definition (`<name>.ts`)\nImplement `ModuleDefinition` interface.\nDefine attributes, relations, and register the definition using `registerDefinition`.\nIf the module is behind a feature flag, set `featureFlag: <FLAG_CONSTANT>` on **each**\nattribute and nested mapping — see the `add-feature-flag` skill.\n\n### Step 8a — Create GraphQL Registration File (`<name>-graphql.ts`)\nCreate a `<name>-graphql.ts` file in the module folder that imports the module schema/resolvers and calls `registerGraphqlSchema(...)`.\n\n### Step 8b — Register Module in `src/modules/index.ts`\nAdd two distinct imports in `src/modules/index.ts`:\n1. In the **`region registration modules`** section, import `./<entityName>/<entityName>` (module definition registration).\n2. In the **`region graphql registration`** section, import `./<entityName>/<entityName>-graphql` (GraphQL endpoint registration).\n\n### Step 8c — Update GraphQL Unions (if applicable)\nIf the entity belongs to a STIX union type (e.g., `StixObject`, `StixDomainObject`), add it to the relevant unions in `src/schema/opencti.graphql`.\n\n### Step 8d — Regenerate Schema Types\nRun `yarn build:schema` to regenerate TypeScript types from the updated schema.\n",".github/skills/create-creation-form/SKILL.md":"---\nname: create-creation-form\ndescription: \"Use when: scaffolding a creation form drawer with Formik validation and a Relay mutation for a new entity\"\n---\n\n# Create Creation Form (Drawer)\n\n## Prerequisites\n- **Mutation**: GraphQL mutation for creating the entity.\n- **Fields**: List of fields to display.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing creation form in `opencti-platform/opencti-front/src/private/components/` (look for files ending in `Creation.tsx`). Model the new form after the existing one to stay idiomatic.\n\n### Step 1 — Define Mutation & Validation\nUse `Yup` for validation schema.\n\n```tsx\nconst creationMutation = graphql`\n  mutation MyEntityCreationMutation($input: MyEntityAddInput!) {\n    myEntityAdd(input: $input) {\n      ...MyEntityLine_node\n    }\n  }\n`;\n\nconst validationSchema = Yup.object().shape({\n  name: Yup.string().required(t('This field is required')),\n});\n```\n\n### Step 2 — Create Component Structure\nReturn a `Drawer` containing a `Formik` form.\n\n```tsx\nexport const MyEntityCreation: React.FC<Props> = ({ paginationOptions }) => {\n  const [commit] = useApiMutation(creationMutation);\n  \n  const onSubmit = (values, { setSubmitting, resetForm }) => {\n    commit({\n      variables: {\n        input: values,\n      },\n      updater: (store) => {\n        // Use utils/store helper\n        insertNode(store, 'Pagination_myEntities', paginationOptions, 'myEntityAdd');\n      },\n      onCompleted: () => {\n        setSubmitting(false);\n        resetForm();\n      },\n    });\n  };\n\n  return (\n    <Drawer title={t_i18n('Create entity')}>\n      <Formik initialValues={{ name: '' }} validationSchema={validationSchema} onSubmit={onSubmit}>\n         <Form>\n            <Field component={TextField} name=\"name\" label={t_i18n('Name')} />\n             <Button type=\"submit\">{t_i18n('Create')}</Button>\n         </Form>\n      </Formik>\n    </Drawer>\n  );\n};\n```\n",".github/skills/create-migration/SKILL.md":"---\nname: create-migration\ndescription: \"Use when: creating a new ElasticSearch database migration file, adding or transforming data at deploy time\"\n---\n\n# Create Database Migration\n\n## Prerequisites\n- **Description**: Short snake_case description of the change (e.g., `add_description_to_user`).\n\n## Procedure\n\n### Step 1 — Generate Migration File\nUse the current timestamp (ms) as prefix.\nFile: `opencti-platform/opencti-graphql/src/migrations/<timestamp>-<description>.ts`.\n\n### Step 2 — Implement Migration Pattern\nUse the standard template with logging and execution context.\n\n```typescript\nimport { logMigration } from '../config/conf';\n\nconst message = '[MIGRATION] <Description>';\n\nexport const up = async (next: (error?: Error) => void) => {\n  const startTime = Date.now();\n  logMigration.info(`${message} > started`);\n\n  // Implementation here\n  // usage: const context = executionContext('migration');\n  //        await someDomainFunction(context, SYSTEM_USER, args);\n\n  logMigration.info(`${message} > done in ${Date.now() - startTime} ms`);\n  next();\n   };\n\nexport const down = async (next: (error?: Error) => void) => {\n  next();\n};\n```\n","AGENTS.md":"# AGENTS.md — OpenCTI\n\nRepository conventions live in `.github/copilot-instructions.md` and\n`.github/instructions/`. This file covers one thing they do not: the Filigran\nDesign System, which is migrating into this product.\n\n`CLAUDE.md` is a one-line import of this file.\n\n## The priority rule\n\n> If the design system ships the component, using it is mandatory.\n> If the design system does not ship it yet, MUI is the fallback, and the gap\n> must be recorded.\n\nThis paragraph is a copy. The single source is `AGENTS.md` §4 in\n[filigran-design-system](https://github.com/XTM-Foundation/filigran-design-system);\nif the two ever disagree, that one wins.\n\nWhich components are already in service **here** is data, not memory:\n\n```bash\nnode fds-migration/scripts/check-mui-regression.mjs --explain\n```\n\nIt prints what is enforced, what is held while the library settles its API, and\nwhat has no MUI counterpart at all. Record a gap in\n`fds-migration/LIBRARY-FEEDBACK.md`.\n\n## Onboarding — first session in this repo\n\n1. Read this file, then `.github/copilot-instructions.md`.\n2. Touching the front end? Run `--explain` above before writing UI code.\n   Touching the back end? Read `.github/instructions/backend.instructions.md`.\n   Adding or removing a feature flag? Follow `.github/skills/add-feature-flag/SKILL.md` —\n   new attribute definitions need `featureFlag`, not only `@ff` and `isFeatureEnabled`.\n3. Read `fds-migration/AGENTS.md` before changing anything under\n   `fds-migration/` or any file listed in `migration-state.json`'s `wiredFiles`.\n\nWhat will stop you:\n\n| Gate | Fires when |\n|---|---|\n| `check-mui-regression.mjs` | New code imports a MUI component the design system already replaces here |\n| `check-fds-conformity.mjs` | A generated bridge file was hand-edited, went stale, or a hardcoded value returned to a migrated zone |\n\nBoth run in CI on every pull request and go red on a violation. Run them\nlocally first — they name file and line, and never need re-deriving by hand.\nWhether a red one also *prevents* the merge depends on the repository's\nrequired-check settings, which are an administrator's to set.\n\nNever hand-edit a file carrying a `GENERATED` header: fix the source in the\ndesign system repo and regenerate.\n",".github/agents/codebase-locator.agent.md":"# Subagent: codebase-locator.agent\n\nPath: `.github/agents/codebase-locator.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-locator.agent.md)",".github/agents/codebase-pattern-finder.agent.md":"# Subagent: codebase-pattern-finder.agent\n\nPath: `.github/agents/codebase-pattern-finder.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-pattern-finder.agent.md)","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json)","opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json)","opencti-platform/opencti-graphql/src/rules/README.md":"# Rules Skill\n\nPath: `opencti-platform/opencti-graphql/src/rules/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-graphql/src/rules/README.md)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md — OpenCTI\n\nRepository conventions live in `.github/copilot-instructions.md` and\n`.github/instructions/`. This file covers one thing they do not: the Filigran\nDesign System, which is migrating into this product.\n\n`CLAUDE.md` is a one-line import of this file.\n\n## The priority rule\n\n> If the design system ships the component, using it is mandatory.\n> If the design system does not ship it yet, MUI is the fallback, and the gap\n> must be recorded.\n\nThis paragraph is a copy. The single source is `AGENTS.md` §4 in\n[filigran-design-system](https://github.com/XTM-Foundation/filigran-design-system);\nif the two ever disagree, that one wins.\n\nWhich components are already in service **here** is data, not memory:\n\n```bash\nnode fds-migration/scripts/check-mui-regression.mjs --explain\n```\n\nIt prints what is enforced, what is held while the library settles its API, and\nwhat has no MUI counterpart at all. Record a gap in\n`fds-migration/LIBRARY-FEEDBACK.md`.\n\n## Onboarding — first session in this repo\n\n1. Read this file, then `.github/copilot-instructions.md`.\n2. Touching the front end? Run `--explain` above before writing UI code.\n   Touching the back end? Read `.github/instructions/backend.instructions.md`.\n   Adding or removing a feature flag? Follow `.github/skills/add-feature-flag/SKILL.md` —\n   new attribute definitions need `featureFlag`, not only `@ff` and `isFeatureEnabled`.\n3. Read `fds-migration/AGENTS.md` before changing anything under\n   `fds-migration/` or any file listed in `migration-state.json`'s `wiredFiles`.\n\nWhat will stop you:\n\n| Gate | Fires when |\n|---|---|\n| `check-mui-regression.mjs` | New code imports a MUI component the design system already replaces here |\n| `check-fds-conformity.mjs` | A generated bridge file was hand-edited, went stale, or a hardcoded value returned to a migrated zone |\n\nBoth run in CI on every pull request and go red on a violation. Run them\nlocally first — they name file and line, and never need re-deriving by hand.\nWhether a red one also *prevents* the merge depends on the repository's\nrequired-check settings, which are an administrator's to set.\n\nNever hand-edit a file carrying a `GENERATED` header: fix the source in the\ndesign system repo and regenerate.\n","isInternal":false,"tokens":557,"sizeBytes":2247},{"name":"AGENTS.md","path":"fds-migration/AGENTS.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/fds-migration/AGENTS.md","title":"fds-migration - AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md — fds-migration (OpenCTI)\n\nGENERATED — do not edit by hand. Regenerate: `pnpm generate:fds-migration --product opencti --write-to-product` (filigran-design-system repo).\n\nThis file is the agent contract for the Filigran Design System migration\nwork in this repo. Read it before touching anything under `fds-migration/`\nor any file listed in `migration-state.json`'s `wiredFiles`.\n\n## Source of truth\n\nTokens, components and their docs live in a separate repo:\n`@filigran/design-system` — the sibling `filigran-design-system/` checkout\nin the Filigran workspace. This repo NEVER defines a design-system token\nlocally: every color, spacing, radius and typography value used here traces\nback to `filigran-design-system/packages/filigran-design-system/src/tokens/theme.css`.\n\nFull machine-readable reference: <https://silver-doodle-mnyv84e.pages.github.io/llms-full.txt>\n(same content as the sibling checkout's `filigran-design-system/llms-full.txt`,\nserved by the docs site).\n\n## Non-negotiable rules\n\n1. **Never hand-edit a generated file.** `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` and its sidecar\n   `.meta.json` are produced by `pnpm generate:mui-bridge` in the\n   filigran-design-system repo. If a value looks wrong, fix `theme.css`\n   upstream (a Figma export, delivered by a human designer) — never patch\n   the generated file here.\n2. **Never invent a token value.** A color/spacing/typography value with no\n   design-system equivalent is a gap to flag (TOKEN-MAPPING.md, section\n   \"Tokens to create in Figma\"), not something to improvise.\n3. **Branch discipline.** All work happens on `fds/*` branches, never on\n   this product's main/master. Run `git branch --show-current` before\n   every commit. No push to any remote without explicit human validation.\n4. **Missing component → flag, never fork.** If a design-system component\n   doesn't exist yet for something you're migrating, report the gap\n   (filigran-design-system's `process/AI-BACKLOG.md` or `ROADMAP.json`)\n   and move on — never build a local approximation.\n5. **The component phase has started — declare every adoption.** Wiring\n   token *values* into the product's MUI theme (IMPLEMENTATION-ROADMAP.md,\n   \"Phase 1\") is no longer the only workstream: products now replace their\n   own container/control components with design-system ones. What changed\n   is not that anything goes — it is that adoptions must be **declared**,\n   not merely written.\n\n   Every adopted component gets an entry in `migration-state.json`'s\n   `libComponentUsage`: the component name, `importFrom`, the exact list\n   of files, the guards it runs under (`imported-from-library`,\n   `no-hardcoded-padding`), and a `reason`. An adoption absent from that\n   list is invisible to `check-fds-conformity.mjs` — it will not be caught\n   when it silently reverts to MUI or when a hardcoded padding creeps back.\n\n   **An agent may convert a component when all four hold:**\n   1. the design-system component **exists** and the capability is verified\n      on the **installed build** (`node_modules`), not on its types, its\n      meta or the changelog;\n   2. the visual delta has been **measured** and either is iso, or is a\n      change a human explicitly asked for — never \"close enough\" chosen\n      silently;\n   3. the conversion loses **no** function, information or interaction —\n      where it would, the site is listed with its reason instead of forced;\n   4. the adoption is **declared** in `libComponentUsage` in the same\n      change set as the code.\n\n   If any of the four fails, stop and report the gap (this repo's\n   `process/AI-BACKLOG.md`) rather than approximate it locally. Rule 4\n   above still applies in full: a missing component is flagged, never\n   forked.\n\n## Where things are\n\n| What | Where |\n|---|---|\n| Generated token data | `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` (+ `.meta.json` sidecar) |\n| Token → theme-field wiring decisions | `fds-migration/TOKEN-MAPPING.md` |\n| What to migrate, in what order, current state | `fds-migration/IMPLEMENTATION-ROADMAP.md` |\n| Session journal (append, never rewrite) | `fds-migration/IMPLEMENTATION-LOG.md` |\n| MUI component → design-system component reference | `fds-migration/COMPONENT-MAPPING.md` |\n| Conformity check (run before every commit touching a wired file) | `node fds-migration/scripts/check-fds-conformity.mjs` |\n| Upstream state manifest | `filigran-design-system/ROADMAP.json` (`implementations`, id `tokens-opencti`) |\n\n## Conformity check\n\nRun `node fds-migration/scripts/check-fds-conformity.mjs` before committing\nany change to a file listed in `migration-state.json`'s `wiredFiles`. It\nverifies the generated bridge file hasn't been hand-edited, that wired\nfiles still import it, and that no hardcoded value has crept back into a\nmigrated zone. Fix everything it reports before committing — it lists\nconcrete file:line issues, it does not need re-deriving by hand.\n\n### Declaring a component-adoption site (`libComponentUsage`)\n\nOnce a real design-system COMPONENT (not just its tokens) is adopted in a\nfile, declare it in `migration-state.json`'s `libComponentUsage` so the\ncheck keeps watching it:\n\n```jsonc\n\"libComponentUsage\": [\n  {\n    \"component\": \"Paper\",\n    \"importFrom\": \"@filigran/design-system\",\n    \"files\": [\"opencti-front/src/.../PanelWidget.tsx\"],\n    \"guards\": [\"imported-from-library\", \"no-hardcoded-padding\"],\n    \"reason\": \"Paper owns padding as a typed prop (0|8|16|24|32) since the Phase 0 round\"\n  }\n]\n```\n\nTwo things to know before writing one:\n\n- **You declare intent, never a pattern.** `guards` names checks the design\n  system implements and maintains; an unknown name is reported `INVALID`\n  rather than passing quietly, so a typo can never read as coverage. Run\n  the check with an obviously wrong name once if you want to see the list.\n- **The scan is structural, not textual.** Each `<Component …>` opening tag\n  is walked to its own closing `>` with quotes, template literals and `{}`\n  nesting tracked, after comments are stripped — so a multiline element is\n  the normal case, a padding on a sibling element is not attributed to this\n  one, and a commented-out class cannot produce a finding. Findings name one\n  element and one line.\n\nAvailable guards today:\n\n| Guard | What it catches |\n|---|---|\n| `imported-from-library` | the component is rendered but no longer imported from the library, or has fallen back to `@mui/material` — a revert the JSX alone cannot show |\n| `no-hardcoded-padding` | a rendered instance sets padding through `className`, `sx` or `style` instead of the component's own `padding` prop, re-forking a scale the component now owns |\n\n## Notes\n\nMUI 6.5 + @mui/styles legacy. Theme files: src/components/ThemeDark.ts / ThemeLight.ts.\n","isInternal":false,"tokens":1694,"sizeBytes":6829},{"name":"SKILL.md","path":".github/skills/add-feature-flag/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/add-feature-flag/SKILL.md","title":"add-feature-flag","category":"anthropic-skill","format":"markdown","content":"---\nname: add-feature-flag\ndescription: \"Use when: putting a new or existing feature behind a feature flag (dev feature) in OpenCTI, adding attributes, GraphQL endpoints, managers or UI that must be hidden until a flag is enabled, or removing a feature flag\"\n---\n\n# Add a Feature Flag\n\nFull rules and rationale: [Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n## Prerequisites\n- **Flag name**: UPPER_SNAKE_CASE string (e.g. `MY_FEATURE`) and its constant (`MY_FEATURE_FEATURE_FLAG`).\n- **Scope**: list of new attributes / mappings, GraphQL endpoints, domain entry points and UI screens of the feature.\n\n## Procedure\n\n### Step 1 — Declare the constant\nAdd `export const MY_FEATURE_FEATURE_FLAG = 'MY_FEATURE';` with a one-line comment in\n`opencti-platform/opencti-graphql/src/config/conf.js`, next to the other flags.\n\n### Step 2 — Flag every new attribute definition (DO NOT SKIP)\nFor **each** attribute added by the feature — in a module definition's `attributes`, in\n`src/modules/attributes/*-registrationAttributes.ts`, or as a new entry in the `mappings`\nof an object attribute — add:\n```ts\nfeatureFlag: MY_FEATURE_FEATURE_FLAG,\n```\nWithout it the field is pushed into the ElasticSearch index mapping at startup even when\nthe flag is off, and nothing fails. Re-read every attribute you added before moving on.\n\n### Step 3 — Gate GraphQL endpoints\nAdd `@ff(flags: [\"MY_FEATURE\"])` to every new query, mutation and field\n(`softFail: true` for fields read early by the front end). Run `yarn build:schema`.\n\n### Step 4 — Gate domain logic\n`enforceEnableFeatureFlag(MY_FEATURE_FEATURE_FLAG)` at the start of mutations / entry\npoints; `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)` for conditional branches.\n\n### Step 5 — Gate managers\n- **New manager:** import `ManagerDefinition` and `registerManager` from `src/manager/managerModule.ts`.\n  Import the new manager file for side effects in `src/manager/index.ts`, and register it with\n  `if (isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)) { registerManager(DEFINITION); }`.\n  Gate the registration, never `enabled()` / `enabledToStart()`: a registered manager shows\n  in the platform modules and startup logs even when the flag is off. Keep its own\n  `enabledByConfig` config. Do not add it to `src/managers.ts`.\n- **Existing manager:** leave its registration alone; branch inside the handler with\n  `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)`.\n\nReference: `src/manager/workflowStatusCleanupManager.ts`. Details in the Managers section of\n[Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n### Step 6 — Gate the UI\n`const { isFeatureEnable } = useHelper();` then `isFeatureEnable('MY_FEATURE')` around\nmenus, routes, tabs and form fields. Run `yarn relay` if GraphQL changed.\n\n### Step 7 — Verify\n- `grep -rn \"featureFlag: MY_FEATURE_FEATURE_FLAG\"` lists **every** new attribute and mapping.\n- With fresh test indices, start the platform with the flag disabled: new attributes are absent\n  from the index mapping and attribute registry. GraphQL fields remain in the schema, but\n  flagged resolvers reject access (or return the soft-fail default); the new manager is\n  neither logged at startup nor listed in the platform modules.\n- Start with `APP__ENABLED_DEV_FEATURES='[\"MY_FEATURE\"]'`: the feature works end to end.\n\n## Removing a flag\nDelete the constant, every `featureFlag: MY_FEATURE_FEATURE_FLAG`, every `@ff(...)` and\nevery `enforceEnableFeatureFlag` / `isFeatureEnabled` / `isFeatureEnable` call for it;\nunwrap the `if` around `registerManager`.\nSearch for `MY_FEATURE` in `opencti-graphql` and `opencti-front` and verify that no declarations or guards for this flag remain; retain legitimate feature and manager identifiers.\n","frontmatter":{"name":"add-feature-flag","description":"Use when: putting a new or existing feature behind a feature flag (dev feature) in OpenCTI, adding attributes, GraphQL endpoints, managers or UI that must be hidden until a flag is enabled, or removing a feature flag"},"isInternal":false,"tokens":884,"sizeBytes":3741},{"name":"SKILL.md","path":".github/skills/create-creation-form/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-creation-form/SKILL.md","title":"create-creation-form","category":"anthropic-skill","format":"markdown","content":"---\nname: create-creation-form\ndescription: \"Use when: scaffolding a creation form drawer with Formik validation and a Relay mutation for a new entity\"\n---\n\n# Create Creation Form (Drawer)\n\n## Prerequisites\n- **Mutation**: GraphQL mutation for creating the entity.\n- **Fields**: List of fields to display.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing creation form in `opencti-platform/opencti-front/src/private/components/` (look for files ending in `Creation.tsx`). Model the new form after the existing one to stay idiomatic.\n\n### Step 1 — Define Mutation & Validation\nUse `Yup` for validation schema.\n\n```tsx\nconst creationMutation = graphql`\n  mutation MyEntityCreationMutation($input: MyEntityAddInput!) {\n    myEntityAdd(input: $input) {\n      ...MyEntityLine_node\n    }\n  }\n`;\n\nconst validationSchema = Yup.object().shape({\n  name: Yup.string().required(t('This field is required')),\n});\n```\n\n### Step 2 — Create Component Structure\nReturn a `Drawer` containing a `Formik` form.\n\n```tsx\nexport const MyEntityCreation: React.FC<Props> = ({ paginationOptions }) => {\n  const [commit] = useApiMutation(creationMutation);\n  \n  const onSubmit = (values, { setSubmitting, resetForm }) => {\n    commit({\n      variables: {\n        input: values,\n      },\n      updater: (store) => {\n        // Use utils/store helper\n        insertNode(store, 'Pagination_myEntities', paginationOptions, 'myEntityAdd');\n      },\n      onCompleted: () => {\n        setSubmitting(false);\n        resetForm();\n      },\n    });\n  };\n\n  return (\n    <Drawer title={t_i18n('Create entity')}>\n      <Formik initialValues={{ name: '' }} validationSchema={validationSchema} onSubmit={onSubmit}>\n         <Form>\n            <Field component={TextField} name=\"name\" label={t_i18n('Name')} />\n             <Button type=\"submit\">{t_i18n('Create')}</Button>\n         </Form>\n      </Formik>\n    </Drawer>\n  );\n};\n```\n","frontmatter":{"name":"create-creation-form","description":"Use when: scaffolding a creation form drawer with Formik validation and a Relay mutation for a new entity"},"isInternal":false,"tokens":464,"sizeBytes":1972},{"name":"SKILL.md","path":".github/skills/create-migration/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-migration/SKILL.md","title":"create-migration","category":"anthropic-skill","format":"markdown","content":"---\nname: create-migration\ndescription: \"Use when: creating a new ElasticSearch database migration file, adding or transforming data at deploy time\"\n---\n\n# Create Database Migration\n\n## Prerequisites\n- **Description**: Short snake_case description of the change (e.g., `add_description_to_user`).\n\n## Procedure\n\n### Step 1 — Generate Migration File\nUse the current timestamp (ms) as prefix.\nFile: `opencti-platform/opencti-graphql/src/migrations/<timestamp>-<description>.ts`.\n\n### Step 2 — Implement Migration Pattern\nUse the standard template with logging and execution context.\n\n```typescript\nimport { logMigration } from '../config/conf';\n\nconst message = '[MIGRATION] <Description>';\n\nexport const up = async (next: (error?: Error) => void) => {\n  const startTime = Date.now();\n  logMigration.info(`${message} > started`);\n\n  // Implementation here\n  // usage: const context = executionContext('migration');\n  //        await someDomainFunction(context, SYSTEM_USER, args);\n\n  logMigration.info(`${message} > done in ${Date.now() - startTime} ms`);\n  next();\n   };\n\nexport const down = async (next: (error?: Error) => void) => {\n  next();\n};\n```\n","frontmatter":{"name":"create-migration","description":"Use when: creating a new ElasticSearch database migration file, adding or transforming data at deploy time"},"isInternal":false,"tokens":264,"sizeBytes":1155},{"name":"SKILL.md","path":".github/skills/create-module/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-module/SKILL.md","title":"create-module","category":"anthropic-skill","format":"markdown","content":"---\nname: create-module\ndescription: \"Use when: scaffolding a new backend entity type, domain module, GraphQL schema, resolvers, or STIX converter in opencti-graphql\"\n---\n\n# Create Backend Module\n\n## Prerequisites\n- **Entity Name**: CamelCase (e.g., `MalwareAnalysis`).\n- **Entity Type**: Constant (e.g., `ENTITY_TYPE_MALWARE_ANALYSIS`).\n- **Parent/Category**: e.g., `ABSTRACT_STIX_DOMAIN_OBJECT`.\n\n## Procedure\n\n### Step 1 — Create Directory Structure\nCreate `opencti-platform/opencti-graphql/src/modules/<entityName>`.\n\n### Step 2 — Create Schema File (`<name>.graphql`)\nDefine the Input, Type, Queries, and Mutations.\n\n### Step 3 — Create Type Definition (`<name>-types.ts`)\nDefine TypeScript interfaces for StixObject, StoreEntity, and internal representations.\nExport the `ENTITY_TYPE_X` constant here.\n\n### Step 4 — Create Converter (`<name>-converter.ts`)\nImplement `convert<Name>ToStix` function to map StoreEntity to StixObject.\n\n### Step 5 — Create Domain Logic (`<name>-domain.ts`)\nImplement CRUD functions: `findAll`, `findById`, `add<Name>`, `delete<Name>`.\nUse `listEntities` and `createEntity` from `database/middleware`.\n\n### Step 6 — Create Resolvers (`<name>-resolvers.ts`)\nMap the GraphQL Query/Mutation fields to the functions in `<name>-domain.ts`.\n\n### Step 7 — Create Module Definition (`<name>.ts`)\nImplement `ModuleDefinition` interface.\nDefine attributes, relations, and register the definition using `registerDefinition`.\nIf the module is behind a feature flag, set `featureFlag: <FLAG_CONSTANT>` on **each**\nattribute and nested mapping — see the `add-feature-flag` skill.\n\n### Step 8a — Create GraphQL Registration File (`<name>-graphql.ts`)\nCreate a `<name>-graphql.ts` file in the module folder that imports the module schema/resolvers and calls `registerGraphqlSchema(...)`.\n\n### Step 8b — Register Module in `src/modules/index.ts`\nAdd two distinct imports in `src/modules/index.ts`:\n1. In the **`region registration modules`** section, import `./<entityName>/<entityName>` (module definition registration).\n2. In the **`region graphql registration`** section, import `./<entityName>/<entityName>-graphql` (GraphQL endpoint registration).\n\n### Step 8c — Update GraphQL Unions (if applicable)\nIf the entity belongs to a STIX union type (e.g., `StixObject`, `StixDomainObject`), add it to the relevant unions in `src/schema/opencti.graphql`.\n\n### Step 8d — Regenerate Schema Types\nRun `yarn build:schema` to regenerate TypeScript types from the updated schema.\n","frontmatter":{"name":"create-module","description":"Use when: scaffolding a new backend entity type, domain module, GraphQL schema, resolvers, or STIX converter in opencti-graphql"},"isInternal":false,"tokens":606,"sizeBytes":2515},{"name":"SKILL.md","path":".github/skills/create-playbook-component/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-playbook-component/SKILL.md","title":"create-playbook-component","category":"anthropic-skill","format":"markdown","content":"---\nname: create-playbook-component\ndescription: \"Use when: adding a new playbook automation component, implementing a PlaybookComponent interface, or registering a new playbook step\"\n---\n\n# Create Playbook Component\n\n## Prerequisites\n- **Component ID**: Unique uppercase ID (e.g., `PLAYBOOK_MY_COMPONENT`).\n- **Configuration**: List of fields required from the user.\n\n## Procedure\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-graphql/src/modules/playbook/components/<name>-component.ts`.\n\n### Step 2 — Define Configuration Schema\nDefine a TypeScript interface for the config and a JSONSchema for validation.\n\n```typescript\nexport interface MyComponentConfig {\n  key: string;\n}\n\nconst SCHEMA: JSONSchemaType<MyComponentConfig> = {\n  type: 'object',\n  properties: {\n    key: { type: 'string' },\n  },\n  required: ['key'],\n};\n```\n\n### Step 3 — Implement Component Interface\nImplement `PlaybookComponent<MyComponentConfig>`.\n\n```typescript\nexport const PLAYBOOK_MY_COMPONENT: PlaybookComponent<MyComponentConfig> = {\n  id: 'PLAYBOOK_MY_COMPONENT',\n  name: 'My Component',\n  description: 'Does something useful',\n  icon: 'icon-name',\n  is_entry_point: false,\n  is_internal: true,\n  ports: [{ id: 'out', type: 'out' }],\n  configuration_schema: SCHEMA,\n  schema: async () => SCHEMA,\n  executor: async ({ bundle, playbookNode }) => {\n    // Business logic here\n    const config = playbookNode.configuration;\n    \n    return { output_port: 'out', bundle };\n  },\n};\n```\n\n### Step 4 — Register Component\nImport and add to `PLAYBOOK_COMPONENTS` in `src/modules/playbook/playbook-components.ts`.\n","frontmatter":{"name":"create-playbook-component","description":"Use when: adding a new playbook automation component, implementing a PlaybookComponent interface, or registering a new playbook step"},"isInternal":false,"tokens":379,"sizeBytes":1618},{"name":"SKILL.md","path":".github/skills/create-react-component/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-react-component/SKILL.md","title":"create-react-component","category":"anthropic-skill","format":"markdown","content":"---\nname: create-react-component\ndescription: \"Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query\"\n---\n\n# Create React Component (Relay)\n\n## Prerequisites\n- **Parent Component**: Knowing where this will be used.\n- **Fragment**: The data requirements from GraphQL.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing component in `opencti-platform/opencti-front/src/private/components/` that uses `useFragment`. Model the new component after the existing one to stay idiomatic.\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-front/src/private/components/...`.\n\n### Step 2 — Define Fragment & Props\nUse `graphql` tag and `useFragment`.\n\n```tsx\nimport React from 'react';\nimport { graphql, useFragment } from 'react-relay';\nimport { MyComponent_data$key } from './__generated__/MyComponent_data.graphql';\n\nconst myComponentFragment = graphql`\n  fragment MyComponent_data on EntityType {\n    id\n    name\n    description\n  }\n`;\n\ninterface MyComponentProps {\n  data: MyComponent_data$key;\n}\n\nconst MyComponent: React.FC<MyComponentProps> = ({ data }) => {\n  const node = useFragment(myComponentFragment, data);\n\n  return (\n    <div>\n      <h1>{node.name}</h1>\n      <p>{node.description}</p>\n    </div>\n  );\n};\n\nexport default MyComponent;\n```\n\n### Step 3 — Run Relay Compiler\nRun `yarn relay` to generate the TypeScript types.\n","frontmatter":{"name":"create-react-component","description":"Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query"},"isInternal":false,"tokens":348,"sizeBytes":1496},{"name":"SKILL.md","path":".github/skills/create-workflow/SKILL.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/skills/create-workflow/SKILL.md","title":"create-workflow","category":"anthropic-skill","format":"markdown","content":"---\nname: create-workflow\ndescription: \"Use when: scaffolding a new GitHub Actions CI/CD workflow, adding automation for tests, builds, releases, or security scans\"\n---\n\n# Create GitHub Action Workflow\n\n## Prerequisites\n- **Workflow Name**: e.g., \"Review Security Scans\"\n- **Trigger**: e.g., `pull_request`, `push`\n- **Job Steps**: e.g., checkout, install deps, run scan\n\n## Procedure\n\n### Step 1 — Create Workflow File\nCreate a new file in `.github/workflows/<workflow-name>.yml`.\n\n```yaml\nname: [Workflow Name]\n\non:\n  [Trigger]:\n    branches: [master]\n\njobs:\n  build:\n    runs-on: ubuntu-26.04\n    steps:\n      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1\n      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v7\n        with:\n          node-version: 20\n          cache: 'yarn'\n      - run: corepack enable\n      - run: yarn install --immutable\n      - name: Run Scan\n        run: [Command]\n```\n\n### Step 2 — Verify Job Dependencies\nEnsure any required secrets or environment variables are available.\n\n### Step 3 — Commit\nCommit with format: `[CI] Add <workflow-name> workflow (#<issue-number>)`\n","frontmatter":{"name":"create-workflow","description":"Use when: scaffolding a new GitHub Actions CI/CD workflow, adding automation for tests, builds, releases, or security scans"},"isInternal":false,"tokens":323,"sizeBytes":1155},{"name":"package.json","path":"opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json","title":"Eslint-plugin-custom-rules Skill","category":"anthropic-skill","format":"json","content":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json)","tokens":300,"sizeBytes":298},{"name":"tsconfig.json","path":"opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json","title":"Eslint-plugin-custom-rules Skill","category":"anthropic-skill","format":"json","content":"# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json)","tokens":300,"sizeBytes":300},{"name":"README.md","path":"opencti-platform/opencti-graphql/src/rules/README.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-graphql/src/rules/README.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"# Rules Skill\n\nPath: `opencti-platform/opencti-graphql/src/rules/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-graphql/src/rules/README.md)","tokens":300,"sizeBytes":223},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# OpenCTI Project Instructions\n\n> **Design system** — before writing or changing any UI, read [`AGENTS.md`](../AGENTS.md)\n> at the repository root. It carries the rule on when the Filigran Design System\n> is mandatory and MUI is not, and names the CI gates that enforce it.\n\n> **Deep-dive references** — read the relevant doc before touching the related code:\n> - [Backend Architecture (opencti-graphql)](instructions/backend.instructions.md)\n> - [Frontend Architecture (opencti-front)](instructions/frontend.instructions.md)\n> - [Python Client & Worker](instructions/python.instructions.md)\n> - [Documentation Authoring (docs)](instructions/docs.instructions.md)\n> - [Code Review Guidelines](instructions/code-review.instructions.md)\n\n> **Copilot Skills** (`.github/skills/`) — procedural playbooks, load the relevant one before starting the task:\n> - `create-module` — Scaffold a new backend domain module (entity type, schema, resolvers, converter)\n> - `create-migration` — Create a new ElasticSearch database migration file\n> - `create-react-component` — Create a new Relay-connected React component\n> - `create-creation-form` — Scaffold a creation form drawer (Formik + Relay mutation)\n> - `create-playbook-component` — Add a new playbook automation component\n> - `create-workflow` — Scaffold a new GitHub Actions workflow\n> - `add-feature-flag` — Put a feature behind a feature flag (constant, attribute `featureFlag`, `@ff`, domain, manager and UI gating) or remove one\n\n## Project Overview\n\nOpenCTI is a cyber threat intelligence platform built with a **monorepo structure** containing:\n- **opencti-platform/opencti-graphql**: Node.js/TypeScript GraphQL API backend\n- **opencti-platform/opencti-front**: React/TypeScript frontend with Relay\n- **client-python**: Python library (pycti) for API access\n- **opencti-worker**: Python worker for background tasks\n- **docs**: MkDocs documentation\n\n## Global Commands & Setup\n\n### 1. Enable Corepack (first-time only)\nOnly needed if Yarn is not already available. Run once per machine:\n```bash\ncorepack enable\n```\nDo **not** add this before every command — assume a dev environment already has corepack enabled.\n\n### 2. Copy .yarnrc.yml (first install only)\nOnly needed when running `yarn install` for the first time in a subdirectory that does not already have `.yarnrc.yml`:\n\n```bash\n# Example for backend\ncd opencti-platform/opencti-graphql\ncp ../.yarnrc.yml .yarnrc.yml\nyarn install\n```\n\nDo **not** copy `.yarnrc.yml` before running tests or other commands — it only matters for `yarn install`.\n\n### 3. Root NX Commands (run from repo root)\nThe root `package.json` uses **NX** to orchestrate all workspaces at once. Prefer these over manually running commands in each subdirectory:\n\n```bash\n# Install all dependencies (frontend + backend + Python)\nyarn deps          # without Python virtualenv\nyarn deps:venv     # with Python virtualenv (recommended)\n\n# Start all dev servers\nyarn dev           # without Python virtualenv\nyarn dev:venv      # with Python virtualenv\n\n# Build everything\nyarn build         # without Python virtualenv\nyarn build:venv    # with Python virtualenv\n\n# Run all tests\nyarn test          # without Python virtualenv\nyarn test:venv     # with Python virtualenv\n\n# Lint everything\nyarn lint\n\n# Regenerate GraphQL schema across all packages\nyarn graphql\n```\n\nThe `:venv` variants wrap the command with a Python virtual environment — use them when working on `client-python` or `opencti-worker` and running the backend app.\n\n### 4. Local Development Stack\nStart the necessary infrastructure (Elastic, Redis, RabbitMQ, Silo):\n```bash\ncd opencti-platform/opencti-dev\ndocker compose up -d\n```\n**(ElasticSearch requires `vm.max_map_count=262144`)**\n\n## Common Pitfalls\n\n- **Yarn install fails**: Is `.yarnrc.yml` present in the subdirectory? Run `cp ../.yarnrc.yml .yarnrc.yml` then retry.\n- **Yarn not found**: Run `corepack enable` once.\n- **Python Dependencies**: Backend requires `yarn install:python`.\n- **Relay**: Frontend requires `yarn relay` after any GraphQL changes.\n- **Node Memory**: Use `NODE_OPTIONS=--max_old_space_size=8192` for large builds.\n\n## Safety Rules\n\n### Destructive Git & File Operations\n**NEVER** run any operation that could cause loss of uncommitted work without explicit user approval. This includes:\n- `git reset --hard`, `git checkout -- <file>`, `git clean -fd`\n- `git stash drop`, `git rebase`, `git push --force`\n- Deleting or overwriting files that may contain unsaved changes\n\n**Before** running any such command:\n1. Run `git status` and `git diff` to identify uncommitted or unstaged changes.\n2. Present a **clear, plain-language summary** of exactly what would be lost (e.g. \"This will discard your unsaved changes to `src/foo.ts` and `src/bar.ts`\").\n3. **Wait for explicit approval** before proceeding.\n\n<!-- filigran-conventions:start -->\n## Commit, PR & issue conventions\n\nAll commits, pull requests and issues in this repository follow the\n[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)\nspecification with a GitHub issue reference:\n\n```\ntype(scope?)!?: description (#issue)\n```\n\n- Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `perf`, `test`,\n  `build`, `ci`, `revert`.\n- The description starts with a lowercase letter and has no trailing period;\n  preserve acronyms and proper nouns.\n- The old `[backend]` / `[frontend]` bracket prefixes are discontinued — use a\n  Conventional Commits scope instead.\n- Pull request titles **must** end with the related issue reference, e.g.\n  `(#1234)`, and every pull request must be linked to an issue.\n- Sign your commits.\n\nWhen generating commit messages, PR titles or issue titles, always follow this\nconvention. See [`.github/LABELS.md`](.github/LABELS.md) for the full title and\nlabel taxonomy.\n<!-- filigran-conventions:end -->\n\n\n<!-- filigran-model-policy:start -->\n## GitHub Copilot model usage\n\nTo keep token consumption under control, pick the model that matches the task:\n\n- **Opus 4.6** — reserve for complex work: deep reasoning, large refactors,\n  architecture design, tricky debugging. It is significantly more\n  token-expensive, so it is not the daily driver.\n- **Sonnet / Gemini / GPT** — default for everyday tasks: autocomplete, small\n  fixes, quick questions, code explanations.\n\nWe have a limited token budget — being mindful of the model you pick makes a\nreal difference at scale. Think of Opus as a specialist you call in when you\nreally need it.\n<!-- filigran-model-policy:end -->\n","isInternal":false,"tokens":1587,"sizeBytes":6533},{"name":"codebase-analyzer.agent.md","path":".github/agents/codebase-analyzer.agent.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-analyzer.agent.md","title":"Codebase Analyzer","category":"subagent-persona","format":"markdown","content":"---\nname: Codebase Analyzer\ndescription: Analyzes codebase implementation details. Useful when you need to find detailed information about specific components.\nargument-hint: Call it with human language prompt describing what explanation you're looking for.\ntools: [vscode, read, search]\n---\n\nYou are a specialist at understanding HOW code works. \nYour job is to analyze implementation details, trace data flow, and explain technical workings with precise file:line references.\n\nIn user prompt, keywords are in quotes (eg. \"kill chain phases\").\n\n## CRITICAL: YOUR ONLY JOB IS TO DOCUMENT AND EXPLAIN THE CODEBASE AS IT EXISTS TODAY\n\n- DO NOT suggest improvements or changes unless the user explicitly asks for them\n- DO NOT perform root cause analysis unless the user explicitly asks for them\n- DO NOT propose future enhancements unless the user explicitly asks for them\n- DO NOT critique the implementation or identify \"problems\"\n- DO NOT comment on code quality, performance issues, or security concerns\n- DO NOT suggest refactoring, optimization, or better approaches\n- ONLY describe what exists, how it works, and how components interact\n\n## Core Responsibilities\n\n1. **Analyze Implementation Details**\n  - Read specific files to understand logic\n  - Identify key functions and their purposes\n  - Trace method calls and data transformations\n  - Note important algorithms or patterns\n\n2. **Trace Data Flow**\n  - Follow data from entry to exit points\n  - Map transformations and validations\n  - Identify state changes and side effects\n  - Document API contracts between components\n\n3. **Identify Architectural Patterns**\n  - Recognize design patterns in use\n  - Note architectural decisions\n  - Identify conventions and best practices\n  - Find integration points between systems\n\n4. **Identify data Models links**\n  - Identify relationships between related entities\n\n## Analysis Strategy\n\n### Main folders to look into\n\n- `client-python` - API to interact with backend\n- `opencti-worker` - Asynchronous tasks\n- `opencti-platform/opencti-graphql` - Backend\n- `opencti-platform/opencti-front` - Frontend\n- `docs` - Documentation\n\n### Step 1: Read Entry Points\n\n- Start with main files mentioned in the request\n- Look for exports, public methods, or route handlers\n- Identify the \"surface area\" of the component\n\n### Step 2: Follow the Code Path\n\n- Trace function calls step by step\n- Read each file involved in the flow\n- Note where data is transformed\n- Identify external dependencies\n- Take time to ultrathink about how all these pieces connect and interact\n\n### Step 3: Document Key Logic\n\n- Document business logic as it exists\n- Describe validation, transformation, error handling\n- Explain any complex algorithms or calculations\n- Note configuration or feature flags being used\n- DO NOT evaluate if the logic is correct or optimal\n- DO NOT identify potential bugs or issues\n\n## Important Guidelines\n\n- **Always include file:line references** for claims\n- **Read files thoroughly** before making statements\n- **Trace actual code paths** don't assume\n- **Focus on \"how\"** not \"what\" or \"why\"\n- **Be precise** about function names and variables\n- **Note exact transformations** with before/after\n\n## Output Format\n\nUse file paths from root workspace.\nStructure your analysis like this:\n\n```\n## Analysis: [Feature/Component Name]\n\n### Overview\n[2-3 sentence summary of how it works]\n\n### Entry Points\n- `api/routes.js:45` - POST /webhooks endpoint\n- `handlers/webhook.js:12` - handleWebhook() function\n\n### Core Implementation\n\n#### 1. Request Validation (`handlers/webhook.js:15-32`)\n- Validates signature using HMAC-SHA256\n- Checks timestamp to prevent replay attacks\n- Returns 401 if validation fails\n\n#### 2. Data Processing (`services/webhook-processor.js:8-45`)\n- Parses webhook payload at line 10\n- Transforms data structure at line 23\n- Queues for async processing at line 40\n\n#### 3. State Management (`stores/webhook-store.js:55-89`)\n- Stores webhook in database with status 'pending'\n- Updates status after processing\n- Implements retry logic for failures\n\n### Data Flow\n1. Request arrives at `api/routes.js:45`\n2. Routed to `handlers/webhook.js:12`\n3. Validation at `handlers/webhook.js:15-32`\n4. Processing at `services/webhook-processor.js:8`\n5. Storage at `stores/webhook-store.js:55`\n\n### Key Patterns\n- **Factory Pattern**: WebhookProcessor created via factory at `factories/processor.js:20`\n- **Repository Pattern**: Data access abstracted in `stores/webhook-store.js`\n- **Middleware Chain**: Validation middleware at `middleware/auth.js:30`\n\n### Configuration\n- Webhook secret from `config/webhooks.js:5`\n- Retry settings at `config/webhooks.js:12-18`\n- Feature flags checked at `utils/features.js:23`\n\n### Error Handling\n- Validation errors return 401 (`handlers/webhook.js:28`)\n- Processing errors trigger retry (`services/webhook-processor.js:52`)\n- Failed webhooks logged to `logs/webhook-errors.log`\n```\n\n## What NOT to Do\n\n- Don't guess about implementation\n- Don't skip error handling or edge cases\n- Don't ignore configuration or dependencies\n- Don't make architectural recommendations\n- Don't analyze code quality or suggest improvements\n- Don't identify bugs, issues, or potential problems\n- Don't comment on performance or efficiency\n- Don't suggest alternative implementations\n- Don't critique design patterns or architectural choices\n- Don't perform root cause analysis of any issues\n- Don't evaluate security implications\n- Don't recommend best practices or improvements\n\n## REMEMBER: You are a documentarian, not a critic or consultant\n\nYour sole purpose is to explain HOW the code currently works, with surgical precision and exact references. \nYou are creating technical documentation of the existing implementation, NOT performing a code review or consultation.\n\nThink of yourself as a technical writer documenting an existing system for someone who needs to understand it, not as an engineer evaluating or improving it. \nHelp users understand the implementation exactly as it exists today, without any judgment or suggestions for change.","frontmatter":{"name":"Codebase Analyzer","description":"Analyzes codebase implementation details. Useful when you need to find detailed information about specific components.","argument-hint":"Call it with human language prompt describing what explanation you're looking for.","tools":["vscode","read","search"]},"isInternal":false,"tokens":1321,"sizeBytes":6077},{"name":"codebase-locator.agent.md","path":".github/agents/codebase-locator.agent.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-locator.agent.md","title":"Subagent: codebase-locator.agent","category":"subagent-persona","format":"markdown","content":"# Subagent: codebase-locator.agent\n\nPath: `.github/agents/codebase-locator.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-locator.agent.md)","tokens":300,"sizeBytes":220},{"name":"codebase-pattern-finder.agent.md","path":".github/agents/codebase-pattern-finder.agent.md","rawUrl":"https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-pattern-finder.agent.md","title":"Subagent: codebase-pattern-finder.agent","category":"subagent-persona","format":"markdown","content":"# Subagent: codebase-pattern-finder.agent\n\nPath: `.github/agents/codebase-pattern-finder.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-pattern-finder.agent.md)","tokens":300,"sizeBytes":241}],"systemPromptSnippet":"<yakaai_skills repo=\"OpenCTI-Platform/opencti\">\n<!-- File: AGENTS.md (Tokens: ~557 | Category: root-instruction) -->\n# AGENTS.md — OpenCTI\n\nRepository conventions live in `.github/copilot-instructions.md` and\n`.github/instructions/`. This file covers one thing they do not: the Filigran\nDesign System, which is migrating into this product.\n\n`CLAUDE.md` is a one-line import of this file.\n\n## The priority rule\n\n> If the design system ships the component, using it is mandatory.\n> If the design system does not ship it yet, MUI is the fallback, and the gap\n> must be recorded.\n\nThis paragraph is a copy. The single source is `AGENTS.md` §4 in\n[filigran-design-system](https://github.com/XTM-Foundation/filigran-design-system);\nif the two ever disagree, that one wins.\n\nWhich components are already in service **here** is data, not memory:\n\n```bash\nnode fds-migration/scripts/check-mui-regression.mjs --explain\n```\n\nIt prints what is enforced, what is held while the library settles its API, and\nwhat has no MUI counterpart at all. Record a gap in\n`fds-migration/LIBRARY-FEEDBACK.md`.\n\n## Onboarding — first session in this repo\n\n1. Read this file, then `.github/copilot-instructions.md`.\n2. Touching the front end? Run `--explain` above before writing UI code.\n   Touching the back end? Read `.github/instructions/backend.instructions.md`.\n   Adding or removing a feature flag? Follow `.github/skills/add-feature-flag/SKILL.md` —\n   new attribute definitions need `featureFlag`, not only `@ff` and `isFeatureEnabled`.\n3. Read `fds-migration/AGENTS.md` before changing anything under\n   `fds-migration/` or any file listed in `migration-state.json`'s `wiredFiles`.\n\nWhat will stop you:\n\n| Gate | Fires when |\n|---|---|\n| `check-mui-regression.mjs` | New code imports a MUI component the design system already replaces here |\n| `check-fds-conformity.mjs` | A generated bridge file was hand-edited, went stale, or a hardcoded value returned to a migrated zone |\n\nBoth run in CI on every pull request and go red on a violation. Run them\nlocally first — they name file and line, and never need re-deriving by hand.\nWhether a red one also *prevents* the merge depends on the repository's\nrequired-check settings, which are an administrator's to set.\n\nNever hand-edit a file carrying a `GENERATED` header: fix the source in the\ndesign system repo and regenerate.\n\n<!-- File: fds-migration/AGENTS.md (Tokens: ~1694 | Category: root-instruction) -->\n# AGENTS.md — fds-migration (OpenCTI)\n\nGENERATED — do not edit by hand. Regenerate: `pnpm generate:fds-migration --product opencti --write-to-product` (filigran-design-system repo).\n\nThis file is the agent contract for the Filigran Design System migration\nwork in this repo. Read it before touching anything under `fds-migration/`\nor any file listed in `migration-state.json`'s `wiredFiles`.\n\n## Source of truth\n\nTokens, components and their docs live in a separate repo:\n`@filigran/design-system` — the sibling `filigran-design-system/` checkout\nin the Filigran workspace. This repo NEVER defines a design-system token\nlocally: every color, spacing, radius and typography value used here traces\nback to `filigran-design-system/packages/filigran-design-system/src/tokens/theme.css`.\n\nFull machine-readable reference: <https://silver-doodle-mnyv84e.pages.github.io/llms-full.txt>\n(same content as the sibling checkout's `filigran-design-system/llms-full.txt`,\nserved by the docs site).\n\n## Non-negotiable rules\n\n1. **Never hand-edit a generated file.** `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` and its sidecar\n   `.meta.json` are produced by `pnpm generate:mui-bridge` in the\n   filigran-design-system repo. If a value looks wrong, fix `theme.css`\n   upstream (a Figma export, delivered by a human designer) — never patch\n   the generated file here.\n2. **Never invent a token value.** A color/spacing/typography value with no\n   design-system equivalent is a gap to flag (TOKEN-MAPPING.md, section\n   \"Tokens to create in Figma\"), not something to improvise.\n3. **Branch discipline.** All work happens on `fds/*` branches, never on\n   this product's main/master. Run `git branch --show-current` before\n   every commit. No push to any remote without explicit human validation.\n4. **Missing component → flag, never fork.** If a design-system component\n   doesn't exist yet for something you're migrating, report the gap\n   (filigran-design-system's `process/AI-BACKLOG.md` or `ROADMAP.json`)\n   and move on — never build a local approximation.\n5. **The component phase has started — declare every adoption.** Wiring\n   token *values* into the product's MUI theme (IMPLEMENTATION-ROADMAP.md,\n   \"Phase 1\") is no longer the only workstream: products now replace their\n   own container/control components with design-system ones. What changed\n   is not that anything goes — it is that adoptions must be **declared**,\n   not merely written.\n\n   Every adopted component gets an entry in `migration-state.json`'s\n   `libComponentUsage`: the component name, `importFrom`, the exact list\n   of files, the guards it runs under (`imported-from-library`,\n   `no-hardcoded-padding`), and a `reason`. An adoption absent from that\n   list is invisible to `check-fds-conformity.mjs` — it will not be caught\n   when it silently reverts to MUI or when a hardcoded padding creeps back.\n\n   **An agent may convert a component when all four hold:**\n   1. the design-system component **exists** and the capability is verified\n      on the **installed build** (`node_modules`), not on its types, its\n      meta or the changelog;\n   2. the visual delta has been **measured** and either is iso, or is a\n      change a human explicitly asked for — never \"close enough\" chosen\n      silently;\n   3. the conversion loses **no** function, information or interaction —\n      where it would, the site is listed with its reason instead of forced;\n   4. the adoption is **declared** in `libComponentUsage` in the same\n      change set as the code.\n\n   If any of the four fails, stop and report the gap (this repo's\n   `process/AI-BACKLOG.md`) rather than approximate it locally. Rule 4\n   above still applies in full: a missing component is flagged, never\n   forked.\n\n## Where things are\n\n| What | Where |\n|---|---|\n| Generated token data | `opencti-platform/opencti-front/src/components/fds-tokens.generated.ts` (+ `.meta.json` sidecar) |\n| Token → theme-field wiring decisions | `fds-migration/TOKEN-MAPPING.md` |\n| What to migrate, in what order, current state | `fds-migration/IMPLEMENTATION-ROADMAP.md` |\n| Session journal (append, never rewrite) | `fds-migration/IMPLEMENTATION-LOG.md` |\n| MUI component → design-system component reference | `fds-migration/COMPONENT-MAPPING.md` |\n| Conformity check (run before every commit touching a wired file) | `node fds-migration/scripts/check-fds-conformity.mjs` |\n| Upstream state manifest | `filigran-design-system/ROADMAP.json` (`implementations`, id `tokens-opencti`) |\n\n## Conformity check\n\nRun `node fds-migration/scripts/check-fds-conformity.mjs` before committing\nany change to a file listed in `migration-state.json`'s `wiredFiles`. It\nverifies the generated bridge file hasn't been hand-edited, that wired\nfiles still import it, and that no hardcoded value has crept back into a\nmigrated zone. Fix everything it reports before committing — it lists\nconcrete file:line issues, it does not need re-deriving by hand.\n\n### Declaring a component-adoption site (`libComponentUsage`)\n\nOnce a real design-system COMPONENT (not just its tokens) is adopted in a\nfile, declare it in `migration-state.json`'s `libComponentUsage` so the\ncheck keeps watching it:\n\n```jsonc\n\"libComponentUsage\": [\n  {\n    \"component\": \"Paper\",\n    \"importFrom\": \"@filigran/design-system\",\n    \"files\": [\"opencti-front/src/.../PanelWidget.tsx\"],\n    \"guards\": [\"imported-from-library\", \"no-hardcoded-padding\"],\n    \"reason\": \"Paper owns padding as a typed prop (0|8|16|24|32) since the Phase 0 round\"\n  }\n]\n```\n\nTwo things to know before writing one:\n\n- **You declare intent, never a pattern.** `guards` names checks the design\n  system implements and maintains; an unknown name is reported `INVALID`\n  rather than passing quietly, so a typo can never read as coverage. Run\n  the check with an obviously wrong name once if you want to see the list.\n- **The scan is structural, not textual.** Each `<Component …>` opening tag\n  is walked to its own closing `>` with quotes, template literals and `{}`\n  nesting tracked, after comments are stripped — so a multiline element is\n  the normal case, a padding on a sibling element is not attributed to this\n  one, and a commented-out class cannot produce a finding. Findings name one\n  element and one line.\n\nAvailable guards today:\n\n| Guard | What it catches |\n|---|---|\n| `imported-from-library` | the component is rendered but no longer imported from the library, or has fallen back to `@mui/material` — a revert the JSX alone cannot show |\n| `no-hardcoded-padding` | a rendered instance sets padding through `className`, `sx` or `style` instead of the component's own `padding` prop, re-forking a scale the component now owns |\n\n## Notes\n\nMUI 6.5 + @mui/styles legacy. Theme files: src/components/ThemeDark.ts / ThemeLight.ts.\n\n<!-- File: .github/skills/add-feature-flag/SKILL.md (Tokens: ~884 | Category: anthropic-skill) -->\n---\nname: add-feature-flag\ndescription: \"Use when: putting a new or existing feature behind a feature flag (dev feature) in OpenCTI, adding attributes, GraphQL endpoints, managers or UI that must be hidden until a flag is enabled, or removing a feature flag\"\n---\n\n# Add a Feature Flag\n\nFull rules and rationale: [Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n## Prerequisites\n- **Flag name**: UPPER_SNAKE_CASE string (e.g. `MY_FEATURE`) and its constant (`MY_FEATURE_FEATURE_FLAG`).\n- **Scope**: list of new attributes / mappings, GraphQL endpoints, domain entry points and UI screens of the feature.\n\n## Procedure\n\n### Step 1 — Declare the constant\nAdd `export const MY_FEATURE_FEATURE_FLAG = 'MY_FEATURE';` with a one-line comment in\n`opencti-platform/opencti-graphql/src/config/conf.js`, next to the other flags.\n\n### Step 2 — Flag every new attribute definition (DO NOT SKIP)\nFor **each** attribute added by the feature — in a module definition's `attributes`, in\n`src/modules/attributes/*-registrationAttributes.ts`, or as a new entry in the `mappings`\nof an object attribute — add:\n```ts\nfeatureFlag: MY_FEATURE_FEATURE_FLAG,\n```\nWithout it the field is pushed into the ElasticSearch index mapping at startup even when\nthe flag is off, and nothing fails. Re-read every attribute you added before moving on.\n\n### Step 3 — Gate GraphQL endpoints\nAdd `@ff(flags: [\"MY_FEATURE\"])` to every new query, mutation and field\n(`softFail: true` for fields read early by the front end). Run `yarn build:schema`.\n\n### Step 4 — Gate domain logic\n`enforceEnableFeatureFlag(MY_FEATURE_FEATURE_FLAG)` at the start of mutations / entry\npoints; `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)` for conditional branches.\n\n### Step 5 — Gate managers\n- **New manager:** import `ManagerDefinition` and `registerManager` from `src/manager/managerModule.ts`.\n  Import the new manager file for side effects in `src/manager/index.ts`, and register it with\n  `if (isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)) { registerManager(DEFINITION); }`.\n  Gate the registration, never `enabled()` / `enabledToStart()`: a registered manager shows\n  in the platform modules and startup logs even when the flag is off. Keep its own\n  `enabledByConfig` config. Do not add it to `src/managers.ts`.\n- **Existing manager:** leave its registration alone; branch inside the handler with\n  `isFeatureEnabled(MY_FEATURE_FEATURE_FLAG)`.\n\nReference: `src/manager/workflowStatusCleanupManager.ts`. Details in the Managers section of\n[Feature Flags](../../instructions/backend/patterns/feature-flags.md).\n\n### Step 6 — Gate the UI\n`const { isFeatureEnable } = useHelper();` then `isFeatureEnable('MY_FEATURE')` around\nmenus, routes, tabs and form fields. Run `yarn relay` if GraphQL changed.\n\n### Step 7 — Verify\n- `grep -rn \"featureFlag: MY_FEATURE_FEATURE_FLAG\"` lists **every** new attribute and mapping.\n- With fresh test indices, start the platform with the flag disabled: new attributes are absent\n  from the index mapping and attribute registry. GraphQL fields remain in the schema, but\n  flagged resolvers reject access (or return the soft-fail default); the new manager is\n  neither logged at startup nor listed in the platform modules.\n- Start with `APP__ENABLED_DEV_FEATURES='[\"MY_FEATURE\"]'`: the feature works end to end.\n\n## Removing a flag\nDelete the constant, every `featureFlag: MY_FEATURE_FEATURE_FLAG`, every `@ff(...)` and\nevery `enforceEnableFeatureFlag` / `isFeatureEnabled` / `isFeatureEnable` call for it;\nunwrap the `if` around `registerManager`.\nSearch for `MY_FEATURE` in `opencti-graphql` and `opencti-front` and verify that no declarations or guards for this flag remain; retain legitimate feature and manager identifiers.\n\n<!-- File: .github/skills/create-creation-form/SKILL.md (Tokens: ~464 | Category: anthropic-skill) -->\n---\nname: create-creation-form\ndescription: \"Use when: scaffolding a creation form drawer with Formik validation and a Relay mutation for a new entity\"\n---\n\n# Create Creation Form (Drawer)\n\n## Prerequisites\n- **Mutation**: GraphQL mutation for creating the entity.\n- **Fields**: List of fields to display.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing creation form in `opencti-platform/opencti-front/src/private/components/` (look for files ending in `Creation.tsx`). Model the new form after the existing one to stay idiomatic.\n\n### Step 1 — Define Mutation & Validation\nUse `Yup` for validation schema.\n\n```tsx\nconst creationMutation = graphql`\n  mutation MyEntityCreationMutation($input: MyEntityAddInput!) {\n    myEntityAdd(input: $input) {\n      ...MyEntityLine_node\n    }\n  }\n`;\n\nconst validationSchema = Yup.object().shape({\n  name: Yup.string().required(t('This field is required')),\n});\n```\n\n### Step 2 — Create Component Structure\nReturn a `Drawer` containing a `Formik` form.\n\n```tsx\nexport const MyEntityCreation: React.FC<Props> = ({ paginationOptions }) => {\n  const [commit] = useApiMutation(creationMutation);\n  \n  const onSubmit = (values, { setSubmitting, resetForm }) => {\n    commit({\n      variables: {\n        input: values,\n      },\n      updater: (store) => {\n        // Use utils/store helper\n        insertNode(store, 'Pagination_myEntities', paginationOptions, 'myEntityAdd');\n      },\n      onCompleted: () => {\n        setSubmitting(false);\n        resetForm();\n      },\n    });\n  };\n\n  return (\n    <Drawer title={t_i18n('Create entity')}>\n      <Formik initialValues={{ name: '' }} validationSchema={validationSchema} onSubmit={onSubmit}>\n         <Form>\n            <Field component={TextField} name=\"name\" label={t_i18n('Name')} />\n             <Button type=\"submit\">{t_i18n('Create')}</Button>\n         </Form>\n      </Formik>\n    </Drawer>\n  );\n};\n```\n\n<!-- File: .github/skills/create-migration/SKILL.md (Tokens: ~264 | Category: anthropic-skill) -->\n---\nname: create-migration\ndescription: \"Use when: creating a new ElasticSearch database migration file, adding or transforming data at deploy time\"\n---\n\n# Create Database Migration\n\n## Prerequisites\n- **Description**: Short snake_case description of the change (e.g., `add_description_to_user`).\n\n## Procedure\n\n### Step 1 — Generate Migration File\nUse the current timestamp (ms) as prefix.\nFile: `opencti-platform/opencti-graphql/src/migrations/<timestamp>-<description>.ts`.\n\n### Step 2 — Implement Migration Pattern\nUse the standard template with logging and execution context.\n\n```typescript\nimport { logMigration } from '../config/conf';\n\nconst message = '[MIGRATION] <Description>';\n\nexport const up = async (next: (error?: Error) => void) => {\n  const startTime = Date.now();\n  logMigration.info(`${message} > started`);\n\n  // Implementation here\n  // usage: const context = executionContext('migration');\n  //        await someDomainFunction(context, SYSTEM_USER, args);\n\n  logMigration.info(`${message} > done in ${Date.now() - startTime} ms`);\n  next();\n   };\n\nexport const down = async (next: (error?: Error) => void) => {\n  next();\n};\n```\n\n<!-- File: .github/skills/create-module/SKILL.md (Tokens: ~606 | Category: anthropic-skill) -->\n---\nname: create-module\ndescription: \"Use when: scaffolding a new backend entity type, domain module, GraphQL schema, resolvers, or STIX converter in opencti-graphql\"\n---\n\n# Create Backend Module\n\n## Prerequisites\n- **Entity Name**: CamelCase (e.g., `MalwareAnalysis`).\n- **Entity Type**: Constant (e.g., `ENTITY_TYPE_MALWARE_ANALYSIS`).\n- **Parent/Category**: e.g., `ABSTRACT_STIX_DOMAIN_OBJECT`.\n\n## Procedure\n\n### Step 1 — Create Directory Structure\nCreate `opencti-platform/opencti-graphql/src/modules/<entityName>`.\n\n### Step 2 — Create Schema File (`<name>.graphql`)\nDefine the Input, Type, Queries, and Mutations.\n\n### Step 3 — Create Type Definition (`<name>-types.ts`)\nDefine TypeScript interfaces for StixObject, StoreEntity, and internal representations.\nExport the `ENTITY_TYPE_X` constant here.\n\n### Step 4 — Create Converter (`<name>-converter.ts`)\nImplement `convert<Name>ToStix` function to map StoreEntity to StixObject.\n\n### Step 5 — Create Domain Logic (`<name>-domain.ts`)\nImplement CRUD functions: `findAll`, `findById`, `add<Name>`, `delete<Name>`.\nUse `listEntities` and `createEntity` from `database/middleware`.\n\n### Step 6 — Create Resolvers (`<name>-resolvers.ts`)\nMap the GraphQL Query/Mutation fields to the functions in `<name>-domain.ts`.\n\n### Step 7 — Create Module Definition (`<name>.ts`)\nImplement `ModuleDefinition` interface.\nDefine attributes, relations, and register the definition using `registerDefinition`.\nIf the module is behind a feature flag, set `featureFlag: <FLAG_CONSTANT>` on **each**\nattribute and nested mapping — see the `add-feature-flag` skill.\n\n### Step 8a — Create GraphQL Registration File (`<name>-graphql.ts`)\nCreate a `<name>-graphql.ts` file in the module folder that imports the module schema/resolvers and calls `registerGraphqlSchema(...)`.\n\n### Step 8b — Register Module in `src/modules/index.ts`\nAdd two distinct imports in `src/modules/index.ts`:\n1. In the **`region registration modules`** section, import `./<entityName>/<entityName>` (module definition registration).\n2. In the **`region graphql registration`** section, import `./<entityName>/<entityName>-graphql` (GraphQL endpoint registration).\n\n### Step 8c — Update GraphQL Unions (if applicable)\nIf the entity belongs to a STIX union type (e.g., `StixObject`, `StixDomainObject`), add it to the relevant unions in `src/schema/opencti.graphql`.\n\n### Step 8d — Regenerate Schema Types\nRun `yarn build:schema` to regenerate TypeScript types from the updated schema.\n\n<!-- File: .github/skills/create-playbook-component/SKILL.md (Tokens: ~379 | Category: anthropic-skill) -->\n---\nname: create-playbook-component\ndescription: \"Use when: adding a new playbook automation component, implementing a PlaybookComponent interface, or registering a new playbook step\"\n---\n\n# Create Playbook Component\n\n## Prerequisites\n- **Component ID**: Unique uppercase ID (e.g., `PLAYBOOK_MY_COMPONENT`).\n- **Configuration**: List of fields required from the user.\n\n## Procedure\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-graphql/src/modules/playbook/components/<name>-component.ts`.\n\n### Step 2 — Define Configuration Schema\nDefine a TypeScript interface for the config and a JSONSchema for validation.\n\n```typescript\nexport interface MyComponentConfig {\n  key: string;\n}\n\nconst SCHEMA: JSONSchemaType<MyComponentConfig> = {\n  type: 'object',\n  properties: {\n    key: { type: 'string' },\n  },\n  required: ['key'],\n};\n```\n\n### Step 3 — Implement Component Interface\nImplement `PlaybookComponent<MyComponentConfig>`.\n\n```typescript\nexport const PLAYBOOK_MY_COMPONENT: PlaybookComponent<MyComponentConfig> = {\n  id: 'PLAYBOOK_MY_COMPONENT',\n  name: 'My Component',\n  description: 'Does something useful',\n  icon: 'icon-name',\n  is_entry_point: false,\n  is_internal: true,\n  ports: [{ id: 'out', type: 'out' }],\n  configuration_schema: SCHEMA,\n  schema: async () => SCHEMA,\n  executor: async ({ bundle, playbookNode }) => {\n    // Business logic here\n    const config = playbookNode.configuration;\n    \n    return { output_port: 'out', bundle };\n  },\n};\n```\n\n### Step 4 — Register Component\nImport and add to `PLAYBOOK_COMPONENTS` in `src/modules/playbook/playbook-components.ts`.\n\n<!-- File: .github/skills/create-react-component/SKILL.md (Tokens: ~348 | Category: anthropic-skill) -->\n---\nname: create-react-component\ndescription: \"Use when: creating a new Relay-connected React component, defining a GraphQL fragment, or wiring a component to a query\"\n---\n\n# Create React Component (Relay)\n\n## Prerequisites\n- **Parent Component**: Knowing where this will be used.\n- **Fragment**: The data requirements from GraphQL.\n\n## Procedure\n\n### Step 0 — Find an Existing Example\nUse the **Codebase Pattern Finder** agent to locate a similar existing component in `opencti-platform/opencti-front/src/private/components/` that uses `useFragment`. Model the new component after the existing one to stay idiomatic.\n\n### Step 1 — Create Component File\nLocation: `opencti-platform/opencti-front/src/private/components/...`.\n\n### Step 2 — Define Fragment & Props\nUse `graphql` tag and `useFragment`.\n\n```tsx\nimport React from 'react';\nimport { graphql, useFragment } from 'react-relay';\nimport { MyComponent_data$key } from './__generated__/MyComponent_data.graphql';\n\nconst myComponentFragment = graphql`\n  fragment MyComponent_data on EntityType {\n    id\n    name\n    description\n  }\n`;\n\ninterface MyComponentProps {\n  data: MyComponent_data$key;\n}\n\nconst MyComponent: React.FC<MyComponentProps> = ({ data }) => {\n  const node = useFragment(myComponentFragment, data);\n\n  return (\n    <div>\n      <h1>{node.name}</h1>\n      <p>{node.description}</p>\n    </div>\n  );\n};\n\nexport default MyComponent;\n```\n\n### Step 3 — Run Relay Compiler\nRun `yarn relay` to generate the TypeScript types.\n\n<!-- File: .github/skills/create-workflow/SKILL.md (Tokens: ~323 | Category: anthropic-skill) -->\n---\nname: create-workflow\ndescription: \"Use when: scaffolding a new GitHub Actions CI/CD workflow, adding automation for tests, builds, releases, or security scans\"\n---\n\n# Create GitHub Action Workflow\n\n## Prerequisites\n- **Workflow Name**: e.g., \"Review Security Scans\"\n- **Trigger**: e.g., `pull_request`, `push`\n- **Job Steps**: e.g., checkout, install deps, run scan\n\n## Procedure\n\n### Step 1 — Create Workflow File\nCreate a new file in `.github/workflows/<workflow-name>.yml`.\n\n```yaml\nname: [Workflow Name]\n\non:\n  [Trigger]:\n    branches: [master]\n\njobs:\n  build:\n    runs-on: ubuntu-26.04\n    steps:\n      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1\n      - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 #v7\n        with:\n          node-version: 20\n          cache: 'yarn'\n      - run: corepack enable\n      - run: yarn install --immutable\n      - name: Run Scan\n        run: [Command]\n```\n\n### Step 2 — Verify Job Dependencies\nEnsure any required secrets or environment variables are available.\n\n### Step 3 — Commit\nCommit with format: `[CI] Add <workflow-name> workflow (#<issue-number>)`\n\n<!-- File: opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/package.json)\n\n<!-- File: opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json (Tokens: ~300 | Category: anthropic-skill) -->\n# Eslint-plugin-custom-rules Skill\n\nPath: `opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-front/packages/eslint-plugin-custom-rules/tsconfig.json)\n\n<!-- File: opencti-platform/opencti-graphql/src/rules/README.md (Tokens: ~300 | Category: anthropic-skill) -->\n# Rules Skill\n\nPath: `opencti-platform/opencti-graphql/src/rules/README.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/opencti-platform/opencti-graphql/src/rules/README.md)\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~1587 | Category: copilot-instructions) -->\n# OpenCTI Project Instructions\n\n> **Design system** — before writing or changing any UI, read [`AGENTS.md`](../AGENTS.md)\n> at the repository root. It carries the rule on when the Filigran Design System\n> is mandatory and MUI is not, and names the CI gates that enforce it.\n\n> **Deep-dive references** — read the relevant doc before touching the related code:\n> - [Backend Architecture (opencti-graphql)](instructions/backend.instructions.md)\n> - [Frontend Architecture (opencti-front)](instructions/frontend.instructions.md)\n> - [Python Client & Worker](instructions/python.instructions.md)\n> - [Documentation Authoring (docs)](instructions/docs.instructions.md)\n> - [Code Review Guidelines](instructions/code-review.instructions.md)\n\n> **Copilot Skills** (`.github/skills/`) — procedural playbooks, load the relevant one before starting the task:\n> - `create-module` — Scaffold a new backend domain module (entity type, schema, resolvers, converter)\n> - `create-migration` — Create a new ElasticSearch database migration file\n> - `create-react-component` — Create a new Relay-connected React component\n> - `create-creation-form` — Scaffold a creation form drawer (Formik + Relay mutation)\n> - `create-playbook-component` — Add a new playbook automation component\n> - `create-workflow` — Scaffold a new GitHub Actions workflow\n> - `add-feature-flag` — Put a feature behind a feature flag (constant, attribute `featureFlag`, `@ff`, domain, manager and UI gating) or remove one\n\n## Project Overview\n\nOpenCTI is a cyber threat intelligence platform built with a **monorepo structure** containing:\n- **opencti-platform/opencti-graphql**: Node.js/TypeScript GraphQL API backend\n- **opencti-platform/opencti-front**: React/TypeScript frontend with Relay\n- **client-python**: Python library (pycti) for API access\n- **opencti-worker**: Python worker for background tasks\n- **docs**: MkDocs documentation\n\n## Global Commands & Setup\n\n### 1. Enable Corepack (first-time only)\nOnly needed if Yarn is not already available. Run once per machine:\n```bash\ncorepack enable\n```\nDo **not** add this before every command — assume a dev environment already has corepack enabled.\n\n### 2. Copy .yarnrc.yml (first install only)\nOnly needed when running `yarn install` for the first time in a subdirectory that does not already have `.yarnrc.yml`:\n\n```bash\n# Example for backend\ncd opencti-platform/opencti-graphql\ncp ../.yarnrc.yml .yarnrc.yml\nyarn install\n```\n\nDo **not** copy `.yarnrc.yml` before running tests or other commands — it only matters for `yarn install`.\n\n### 3. Root NX Commands (run from repo root)\nThe root `package.json` uses **NX** to orchestrate all workspaces at once. Prefer these over manually running commands in each subdirectory:\n\n```bash\n# Install all dependencies (frontend + backend + Python)\nyarn deps          # without Python virtualenv\nyarn deps:venv     # with Python virtualenv (recommended)\n\n# Start all dev servers\nyarn dev           # without Python virtualenv\nyarn dev:venv      # with Python virtualenv\n\n# Build everything\nyarn build         # without Python virtualenv\nyarn build:venv    # with Python virtualenv\n\n# Run all tests\nyarn test          # without Python virtualenv\nyarn test:venv     # with Python virtualenv\n\n# Lint everything\nyarn lint\n\n# Regenerate GraphQL schema across all packages\nyarn graphql\n```\n\nThe `:venv` variants wrap the command with a Python virtual environment — use them when working on `client-python` or `opencti-worker` and running the backend app.\n\n### 4. Local Development Stack\nStart the necessary infrastructure (Elastic, Redis, RabbitMQ, Silo):\n```bash\ncd opencti-platform/opencti-dev\ndocker compose up -d\n```\n**(ElasticSearch requires `vm.max_map_count=262144`)**\n\n## Common Pitfalls\n\n- **Yarn install fails**: Is `.yarnrc.yml` present in the subdirectory? Run `cp ../.yarnrc.yml .yarnrc.yml` then retry.\n- **Yarn not found**: Run `corepack enable` once.\n- **Python Dependencies**: Backend requires `yarn install:python`.\n- **Relay**: Frontend requires `yarn relay` after any GraphQL changes.\n- **Node Memory**: Use `NODE_OPTIONS=--max_old_space_size=8192` for large builds.\n\n## Safety Rules\n\n### Destructive Git & File Operations\n**NEVER** run any operation that could cause loss of uncommitted work without explicit user approval. This includes:\n- `git reset --hard`, `git checkout -- <file>`, `git clean -fd`\n- `git stash drop`, `git rebase`, `git push --force`\n- Deleting or overwriting files that may contain unsaved changes\n\n**Before** running any such command:\n1. Run `git status` and `git diff` to identify uncommitted or unstaged changes.\n2. Present a **clear, plain-language summary** of exactly what would be lost (e.g. \"This will discard your unsaved changes to `src/foo.ts` and `src/bar.ts`\").\n3. **Wait for explicit approval** before proceeding.\n\n<!-- filigran-conventions:start -->\n## Commit, PR & issue conventions\n\nAll commits, pull requests and issues in this repository follow the\n[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)\nspecification with a GitHub issue reference:\n\n```\ntype(scope?)!?: description (#issue)\n```\n\n- Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `perf`, `test`,\n  `build`, `ci`, `revert`.\n- The description starts with a lowercase letter and has no trailing period;\n  preserve acronyms and proper nouns.\n- The old `[backend]` / `[frontend]` bracket prefixes are discontinued — use a\n  Conventional Commits scope instead.\n- Pull request titles **must** end with the related issue reference, e.g.\n  `(#1234)`, and every pull request must be linked to an issue.\n- Sign your commits.\n\nWhen generating commit messages, PR titles or issue titles, always follow this\nconvention. See [`.github/LABELS.md`](.github/LABELS.md) for the full title and\nlabel taxonomy.\n<!-- filigran-conventions:end -->\n\n\n<!-- filigran-model-policy:start -->\n## GitHub Copilot model usage\n\nTo keep token consumption under control, pick the model that matches the task:\n\n- **Opus 4.6** — reserve for complex work: deep reasoning, large refactors,\n  architecture design, tricky debugging. It is significantly more\n  token-expensive, so it is not the daily driver.\n- **Sonnet / Gemini / GPT** — default for everyday tasks: autocomplete, small\n  fixes, quick questions, code explanations.\n\nWe have a limited token budget — being mindful of the model you pick makes a\nreal difference at scale. Think of Opus as a specialist you call in when you\nreally need it.\n<!-- filigran-model-policy:end -->\n\n<!-- File: .github/agents/codebase-analyzer.agent.md (Tokens: ~1321 | Category: subagent-persona) -->\n---\nname: Codebase Analyzer\ndescription: Analyzes codebase implementation details. Useful when you need to find detailed information about specific components.\nargument-hint: Call it with human language prompt describing what explanation you're looking for.\ntools: [vscode, read, search]\n---\n\nYou are a specialist at understanding HOW code works. \nYour job is to analyze implementation details, trace data flow, and explain technical workings with precise file:line references.\n\nIn user prompt, keywords are in quotes (eg. \"kill chain phases\").\n\n## CRITICAL: YOUR ONLY JOB IS TO DOCUMENT AND EXPLAIN THE CODEBASE AS IT EXISTS TODAY\n\n- DO NOT suggest improvements or changes unless the user explicitly asks for them\n- DO NOT perform root cause analysis unless the user explicitly asks for them\n- DO NOT propose future enhancements unless the user explicitly asks for them\n- DO NOT critique the implementation or identify \"problems\"\n- DO NOT comment on code quality, performance issues, or security concerns\n- DO NOT suggest refactoring, optimization, or better approaches\n- ONLY describe what exists, how it works, and how components interact\n\n## Core Responsibilities\n\n1. **Analyze Implementation Details**\n  - Read specific files to understand logic\n  - Identify key functions and their purposes\n  - Trace method calls and data transformations\n  - Note important algorithms or patterns\n\n2. **Trace Data Flow**\n  - Follow data from entry to exit points\n  - Map transformations and validations\n  - Identify state changes and side effects\n  - Document API contracts between components\n\n3. **Identify Architectural Patterns**\n  - Recognize design patterns in use\n  - Note architectural decisions\n  - Identify conventions and best practices\n  - Find integration points between systems\n\n4. **Identify data Models links**\n  - Identify relationships between related entities\n\n## Analysis Strategy\n\n### Main folders to look into\n\n- `client-python` - API to interact with backend\n- `opencti-worker` - Asynchronous tasks\n- `opencti-platform/opencti-graphql` - Backend\n- `opencti-platform/opencti-front` - Frontend\n- `docs` - Documentation\n\n### Step 1: Read Entry Points\n\n- Start with main files mentioned in the request\n- Look for exports, public methods, or route handlers\n- Identify the \"surface area\" of the component\n\n### Step 2: Follow the Code Path\n\n- Trace function calls step by step\n- Read each file involved in the flow\n- Note where data is transformed\n- Identify external dependencies\n- Take time to ultrathink about how all these pieces connect and interact\n\n### Step 3: Document Key Logic\n\n- Document business logic as it exists\n- Describe validation, transformation, error handling\n- Explain any complex algorithms or calculations\n- Note configuration or feature flags being used\n- DO NOT evaluate if the logic is correct or optimal\n- DO NOT identify potential bugs or issues\n\n## Important Guidelines\n\n- **Always include file:line references** for claims\n- **Read files thoroughly** before making statements\n- **Trace actual code paths** don't assume\n- **Focus on \"how\"** not \"what\" or \"why\"\n- **Be precise** about function names and variables\n- **Note exact transformations** with before/after\n\n## Output Format\n\nUse file paths from root workspace.\nStructure your analysis like this:\n\n```\n## Analysis: [Feature/Component Name]\n\n### Overview\n[2-3 sentence summary of how it works]\n\n### Entry Points\n- `api/routes.js:45` - POST /webhooks endpoint\n- `handlers/webhook.js:12` - handleWebhook() function\n\n### Core Implementation\n\n#### 1. Request Validation (`handlers/webhook.js:15-32`)\n- Validates signature using HMAC-SHA256\n- Checks timestamp to prevent replay attacks\n- Returns 401 if validation fails\n\n#### 2. Data Processing (`services/webhook-processor.js:8-45`)\n- Parses webhook payload at line 10\n- Transforms data structure at line 23\n- Queues for async processing at line 40\n\n#### 3. State Management (`stores/webhook-store.js:55-89`)\n- Stores webhook in database with status 'pending'\n- Updates status after processing\n- Implements retry logic for failures\n\n### Data Flow\n1. Request arrives at `api/routes.js:45`\n2. Routed to `handlers/webhook.js:12`\n3. Validation at `handlers/webhook.js:15-32`\n4. Processing at `services/webhook-processor.js:8`\n5. Storage at `stores/webhook-store.js:55`\n\n### Key Patterns\n- **Factory Pattern**: WebhookProcessor created via factory at `factories/processor.js:20`\n- **Repository Pattern**: Data access abstracted in `stores/webhook-store.js`\n- **Middleware Chain**: Validation middleware at `middleware/auth.js:30`\n\n### Configuration\n- Webhook secret from `config/webhooks.js:5`\n- Retry settings at `config/webhooks.js:12-18`\n- Feature flags checked at `utils/features.js:23`\n\n### Error Handling\n- Validation errors return 401 (`handlers/webhook.js:28`)\n- Processing errors trigger retry (`services/webhook-processor.js:52`)\n- Failed webhooks logged to `logs/webhook-errors.log`\n```\n\n## What NOT to Do\n\n- Don't guess about implementation\n- Don't skip error handling or edge cases\n- Don't ignore configuration or dependencies\n- Don't make architectural recommendations\n- Don't analyze code quality or suggest improvements\n- Don't identify bugs, issues, or potential problems\n- Don't comment on performance or efficiency\n- Don't suggest alternative implementations\n- Don't critique design patterns or architectural choices\n- Don't perform root cause analysis of any issues\n- Don't evaluate security implications\n- Don't recommend best practices or improvements\n\n## REMEMBER: You are a documentarian, not a critic or consultant\n\nYour sole purpose is to explain HOW the code currently works, with surgical precision and exact references. \nYou are creating technical documentation of the existing implementation, NOT performing a code review or consultation.\n\nThink of yourself as a technical writer documenting an existing system for someone who needs to understand it, not as an engineer evaluating or improving it. \nHelp users understand the implementation exactly as it exists today, without any judgment or suggestions for change.\n\n<!-- File: .github/agents/codebase-locator.agent.md (Tokens: ~300 | Category: subagent-persona) -->\n# Subagent: codebase-locator.agent\n\nPath: `.github/agents/codebase-locator.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-locator.agent.md)\n\n<!-- File: .github/agents/codebase-pattern-finder.agent.md (Tokens: ~300 | Category: subagent-persona) -->\n# Subagent: codebase-pattern-finder.agent\n\nPath: `.github/agents/codebase-pattern-finder.agent.md`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/OpenCTI-Platform/opencti/HEAD/.github/agents/codebase-pattern-finder.agent.md)\n</yakaai_skills>"}