本文へ移動
cccskills
無料GitHub で公開

grafema-batch-plugin-development

How to write a Grafema batch-mode plugin that reads the graph and filesystem, then writes new edges/nodes directly to RFDB. Use when: (1) need to add project-specific edges that generic analyzers can't produce, (2) need to read config files (JSON/YAML) and trace values into code, (3) implementing framework-specific resolvers (Django settings, Express routes, pipeline configs). Covers: grafema.config.yaml plugin config, RFDB field naming (src/dst NOT source/target), addEdges/addNodes API, RFDBServerBackend connection pattern.

インストール方法を見る

含まれるファイル(1)

  • SKILL.md4.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Grafema Batch Plugin Development

Problem

Generic language analyzers (Python, JS, etc.) can't resolve project-specific patterns like config-driven registries, DI containers, or framework routing. Batch plugins bridge this gap by reading both the graph AND filesystem.

Context / Trigger Conditions

  • Need to resolve dynamic dependencies driven by config files (JSON, YAML)
  • Framework-specific patterns: importlib.import_module() + config, DI wiring, event dispatch, route→handler mapping
  • Generic analyzer produces the base graph, but project-specific edges are missing
  • User asks for "project-level plugin" or "config-driven resolution"

Solution

1. Plugin configuration in grafema.config.yaml

plugins:
  - name: my-project-plugin
    command: "node my-plugin.mjs"
    mode: batch  # KEY: batch mode gets RFDB_SOCKET env var

2. Plugin receives environment variables

RFDB_SOCKET=/path/to/.grafema/rfdb.sock
RFDB_DATABASE=default

3. Plugin template (Node.js / ESM)

const { RFDBServerBackend } = await import(
  '/path/to/grafema/packages/util/dist/storage/backends/RFDBServerBackend.js'
);

const backend = new RFDBServerBackend({
  socketPath: process.env.RFDB_SOCKET,
  autoStart: false,  // server already running
});
await backend.connect();

// Read existing graph
const allNodes = await backend.getAllNodes();

// Read project config files (filesystem access!)
import { readFileSync } from 'fs';
const config = JSON.parse(readFileSync('config.json', 'utf-8'));

// Build new edges
const newEdges = [];
// ... resolution logic ...

// CRITICAL: use src/dst, NOT source/target
newEdges.push({
  src: sourceNodeId,     // NOT 'source'
  dst: targetNodeId,     // NOT 'target'
  edgeType: 'MY_EDGE',  // NOT 'type' alone
  metadata: { ... },
});

// Write to RFDB
await backend.addEdges(newEdges);
await backend.flush();
await backend.close();

4. Critical field naming

CorrectWRONG (silent failure)What happens
srcsourceString(undefined) = "undefined" stored
dsttargetSame — edge created with garbage IDs
edgeTypetype onlyWorks but less explicit

As of v0.3.22+, validation throws with helpful hints:

addEdges: edge at index 0 is missing required 'src' field.
Did you mean 'src'? Found 'source' = 'grafema://...'

5. Orchestrator execution order

Analysis (parse files) → Resolution (python-resolve, etc.)
  → User plugins (your batch plugin runs HERE)
    → Unresolved diagnostics → Module dependency derivation → Metrics

Plugin runs AFTER built-in resolution, so it can read resolved edges.

Verification

After grafema analyze, check:

grafema overview --json | jq '.edgesByType'

New edge types from your plugin should appear.

Example: Pipeline Config Resolver

Resolves importlib.import_module(f".stages.{name}") + pipeline_config.json:

// Find importlib calls in graph
const importlibCalls = allNodes.filter(
  n => n.type === 'CALL' && n.name === 'import_module' && n.receiver === 'importlib'
);

// Read config
const stages = config.pipeline.stages.filter(s => s.enabled);

// For each configured stage, emit REGISTRY_WIRES edge
for (const call of importlibCalls) {
  for (const stage of stages) {
    const targetModule = allNodes.find(
      n => n.type === 'MODULE' && n.file === `pkg/stages/${stage.module}.py`
    );
    if (targetModule) {
      newEdges.push({
        src: call.id,
        dst: targetModule.id,
        edgeType: 'REGISTRY_WIRES',
        metadata: { mechanism: 'importlib', config_source: 'pipeline_config.json' },
      });
    }
  }
}

Notes

  • Batch plugins write directly to RFDB — orchestrator reports nodes=0 edges=0 in its log for batch plugins (this is expected, not a bug)
  • Plugin runs from the project root directory (where grafema.config.yaml lives)
  • Plugin stderr goes to orchestrator log; stdout is captured but ignored for batch mode
  • Use depends_on: ["python-resolution"] if your plugin needs resolved edges
  • getAllNodes() returns ALL nodes including METRIC/ISSUE — filter by type
  • Node IDs are URI format: grafema://host/file#TYPE-%3Ename%5Bscope%5D

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Fix Elixir/Erlang AST processing bugs in Grafema beam-analyzer. Use when: (1) Elixir parser returns MODULE node but 0 functions/calls — body nesting issue, (2) Erlang parser crashes with "cannot convert list to string" on OTP 26+ — location format changed from integer to keyword list, (3) pipe operator |> creates spurious CALL nodes instead of desugared function calls — clause ordering bug, (4) multi-module .ex files return only the first module — missing __block__ handler, (5) installing Erlang/Elixir on macOS with outdated Xcode/Clang.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fires after fixing any non-trivial bug or regression. Asks: could the graph have caught this as a guarantee? Pairs with reflection-in-and-on-action — picks up after "earliest catchable signal" and asks the next question: was that signal expressible in graph? Triggers: (1) after any non-trivial bug fix is verified working, (2) after a regression report (something used to work, broke), (3) during step 6 (knowledge extraction) of the workflow, (4) when reflection-on-action surfaces a "would have been catchable" signal. Outcome is a triage decision (graph-reachable? rule expressible? rule sound?) and either a draft Linear issue + guarantee proposal, or a recorded "graph capability gap" note. Never auto-creates guarantees.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Playwright automation failures against code-server (VS Code in browser). Use when: (1) trust dialog blocks all clicks — "monaco-dialog-modal-block intercepts pointer events", (2) button:has-text() finds wrong buttons behind modal dialog, (3) keyboard shortcuts don't work — Meta vs Control inconsistency, (4) VS Code extension activity bar icon not found by aria-label, (5) panels show placeholder text despite extension being "Connected". Covers trust dialog dismissal, keyboard shortcut hybrid mode, extension panel selectors, and database connection verification for Grafema extension.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Systematic methodology for achieving 100% backward dataflow reachability in a new language. Create gauntlet fixture, write trace, diagnose gaps, fix analyzer/algorithm, iterate to 100%. Language-agnostic process. Use when: (1) adding a new language to Grafema, (2) auditing dataflow coverage for existing language, (3) user says "/dataflow-gauntlet".

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix docker exec hanging when starting background processes (servers, daemons) inside containers. Use when: (1) docker exec never returns despite using & or nohup, (2) background server started in container causes docker exec to hang indefinitely, (3) env_startup_command in SWE-bench or similar frameworks times out, (4) setsid/disown needed for proper process detachment in Docker. Root cause: docker exec tracks ALL processes in the exec session, not just the top-level PID.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Fix Node.js CLI tools crashing inside Docker containers when host-installed node_modules require a newer Node version than the container provides. Use when: (1) "SyntaxError: Invalid regular expression flags" with /v flag in string-width or similar packages, (2) node_modules installed on host with Node 20+ but container has Node 18, (3) `npm install` with file: protocol creates symlinks that break inside Docker, (4) pnpm workspace packages become broken symlinks in containers. Covers version detection, Node binary mounting, and npm install strategies for cross-version compatibility.

日本語の概要は準備中です。原文の説明を表示しています。

Disentinel/grafema362026年8月24日 更新

Disentinel のスキルをすべて見る

このスキルの問題を報告する