@x12i/memorix-skill-process
v0.3.4
Published
Process Memorix records through a skill — select by OT/CT filter, run skill with Scoper MCP, markdown→JSON, write output CT
Readme
@x12i/memorix-skill-process
Select Memorix records by OT + structured CT filter, run each through @x12i/memorix-skills, convert markdown skill output to JSON, and write one output content type at the same OT + recordId.
Requires @x12i/memorix-client@^3.8.0, @x12i/ai-dispatcher@^2.0.0, @x12i/memorix-scoper@^2.0.0. See docs/prerequisites.md.
Scoper 2.0 fetches stored records by default. Set options.synthesize: true and objective only when the skill must summarize records it cannot name. The host wrapper does that alignment on scoper__scope / scoper__subject_data.
Flow
- Select —
explore.queryContentonquery.contentType+query.filter→recordId[] - Fetch —
getContentfor eachinputContentTypesentry - Run skill —
skills.run(dispatcher has Scoper MCP attached unlessscoperMcp: false) - Convert — markdown → JSON (
nx-json-parser) - Push —
writeContenttooutputContentTypeonly (OT +recordIdknown)
Usage
import { createMemorixClient } from "@x12i/memorix-client";
import { createMemorixSkillProcess } from "@x12i/memorix-skill-process";
const memorix = createMemorixClient({ /* baseUrl, orgId, agentIds, caller */ });
// Omit scoperMcp to auto-attach from memorix config; or pass createUniqueTraceScoperMcp(...).
// Pass dispatcher options (not a live dispatcher) so Scoper can be merged.
const process = await createMemorixSkillProcess({
memorix,
skills: {
dispatcher: {
openrouter: { apiKey: process.env.OPENROUTER_API_KEY },
},
},
});
const result = await process.run({
skill: "echo-records",
objectType: "employees",
inputContentTypes: ["raw"],
query: {
contentType: "raw",
filter: { "data.status": "open" },
},
outputContentType: "skill-summary",
request: { provider: "openrouter", model: "openai/gpt-5.2" },
});Scoper MCP attach
- Omit
scoperMcp: auto-build from Memorix config when this factory creates the dispatcher. - Pass servers: merge into dispatcher options.
scoperMcp: false: skip Scoper (unit tests / preload-only).- Do not pass a live
AiDispatcher/MemorixSkillstogether withscoperMcp— that throwsSCOPER_MCP_ATTACH_SKIPPED. Pre-wire withcreateDispatcherWithScoperMcpand omit top-levelscoperMcpinstead.
Cloud models only see tool schemas; callTool runs on the host (VPN reachability to Memorix is required on the host, not on OpenRouter).
Notes
- Output catalog: skill-api startup and each analysis sequence load the full agent pack, add every pipeline output content type that is missing (
{ id }only; other content types stay), and callensureMetadataonce (confirm: true). The same checksum is a noop.ready: falsestops the process before it writes. A write refused withROUTE_UNKNOWN_CONTENT_TYPEdeclares that one content type and retries once. - Per-record isolation: one skill run per
recordId. Errors on one record do not stop the loop. concurrency(default1): bounded parallel fetch → skill → write; result order matchesrecordIds.skipIfOutputExists: skip when the output CT already exists (safe restarts).- Empty skill text or non-object markdown→JSON fails that record (no raw markdown push).
- Write-back: skill JSON is written as
record.dataonly.- If the output CT already exists →
op: "patch"with[{ op: "set", path: "data", value }]. - If absent →
op: "add"with{ recordId, data }plusconcept/dataCategorycopied from an input CT for the same subject (never invented). - Memorix owns format, revision,
_system, and keeps concept on updates (buildMutatedRecord).
- If the output CT already exists →
- Filter accepts equality maps or SafeFilter (
@x12i/memorix-clientContentQueryFilter).
Analysis sequence
# Smoke (2 records per step)
node --env-file=.env packages/skill-process/scripts/run-analysis-sequence.mjs
# Full estate, concurrency 8 — effort: low by default; high for
# attack surface, asset triage, and deepen on exploitable+reachable assets
CONCURRENCY=8 node --env-file=.env packages/skill-process/scripts/run-analysis-sequence.mjs --fullGeneric single step:
node --env-file=.env packages/skill-process/scripts/run-skill-batch.mjs \
--skill=analyze-endpoint-asset --objectType=endpoint-asset \
--inputContentTypes=inventory --queryContentType=inventory \
--outputContentType=analysis --discriminatorValue=asset-exposure \
--reasoningEffort=high --maxRecords=1