Parism

Analizador estructurado de salida de shell para agentes de IA — servidor MCP

Documentación

Parism

Refract the Shell. Every command, structured.

한국어 | English

Un servidor MCP y biblioteca de Node.js que permite a los agentes de IA ejecutar comandos de shell de forma segura y recibir los resultados como JSON.

Documentación: SPECIFICATION · SECURITY · CHANGELOG


Resumen

run({ "cmd": "ls", "args": ["-la", "src"] })
{
  "ok": true,
  "stdout": {
    "raw": "drwxr-xr-x  2 user group 4096 Mar 06 09:23 src\n",
    "parsed": {
      "entries": [
        {
          "type": "directory",
          "name": "src",
          "permissions": { "owner": "rwx", "group": "r-x", "other": "r-x" },
          "size_bytes": 4096,
          "owner": "user",
          "group": "group",
          "modified_at": "2026-03-06T09:23:00"
        }
      ]
    }
  }
}
  • raw siempre contiene la salida original sin modificar.
  • parsed contiene la estructura que el analizador extrajo. Para comandos sin analizador, es null.
  • Hay analizadores predeterminados para 43 comandos, y puedes agregar los tuyos propios.

La salida del shell está diseñada para ser leída por humanos. Si un agente la interpreta directamente, a menudo se equivoca con espacios en nombres de archivo, órdenes de columnas específicos del sistema operativo (ps) y encabezados que varían según el entorno (df). Parism detecta el sistema operativo, elige el analizador correcto y devuelve el resultado interpretado.


Estructura de funcionamiento

  Agent (MCP client)                 Node.js code
         │  stdio                          │  createEngine()
         ▼                                 ▼
  ┌──────────────────────────────────────────────────┐
  │                     Parism                       │
  │                                                  │
  │  1. Guard      allowlist · paths · injection     │──▶ blocked: ok=false, failure.kind="guard"
  │       │                                          │
  │  2. Executor   spawn (no shell), timeout, limit  │──▶ exec error: failure.kind="exec"
  │       │                                          │
  │  3. Redactor   mask secrets in output            │
  │       │                                          │
  │  4. Parser     OS-aware, 43 built-in + custom    │──▶ no parser: parsed=null, raw kept
  │       │                                          │
  │  5. Shaper     filter · budget · evidence        │
  │       │                                          │
  │       ├──▶ Result store (opt-in, in memory)      │
  └───────┼──────────────────────────────────────────┘
          ▼
   { ok, stdout: { raw, parsed }, failure?, review?, budget? }

Los comandos se ejecutan directamente como ejecutables, sin pasar por el shell. El bloqueo, el fallo de ejecución y el fallo de análisis devuelven respuestas con el mismo formato, sin lanzar excepciones. El agente solo necesita ramificar con failure.kind.


Inicio rápido

1. Instalación

npx @nerdvana/parism

Si se ejecuta sin argumentos, funciona como servidor MCP stdio. Para compilar desde el código fuente, haz lo siguiente.

git clone https://github.com/JinHo-von-Choi/parism
cd parism
npm install && npm run build
node dist/index.js

2. Registro en el cliente MCP

La mayoría de los clientes aceptan el siguiente formato directamente.

{
  "mcpServers": {
    "parism": {
      "command": "npx",
      "args": ["-y", "@nerdvana/parism"]
    }
  }
}

La ubicación de configuración específica de cada cliente está en los siguientes documentos.

ClienteDocumento
Claude Desktopclaude-desktop.md
Claude Codeclaude-code.md
Cursorcursor.md
Gemini CLIgemini-cli.md
Codex CLIcodex.md
GitHub Copilot CLIcopilot-cli.md

3. Orden de la primera llamada del agente

describe()                    허용 명령, 파서, 가드 제한 확인
   │
dry_run(cmd, args)            가드 통과 여부만 확인 (실행 안 함)
   │
run(cmd, args)                실행하고 구조화된 결과 받기
   │
   ├─ 출력이 크면  ──▶ run_paged(page=N)  또는  run(budget) + fetch_result
   └─ 근거가 필요하면 ──▶ run(retain, evidence) + explain_result

Herramientas

Al conectarse, se exponen 7 herramientas.

HerramientaEjecuta comandosPropósito
runOEjecución básica. Incluye opciones de filtro, presupuesto y justificación
run_pagedOLeer salidas grandes en páginas por líneas
describeXVerificar entorno, comandos permitidos e información del analizador
dry_runXVerificar de antemano si se superan las protecciones
explain_resultXConsultar de dónde proviene un valor en el texto original de un resultado archivado
fetch_resultXLeer la siguiente página de un resultado truncado por presupuesto
compare_resultsXComparar las diferencias entre dos resultados archivados

explain_result, fetch_result, compare_results solo leen resultados archivados y no vuelven a ejecutar el comando. Las copias archivadas residen únicamente en la memoria del proceso del servidor, con un límite de 2MiB por resultado, 32MiB en total, máximo 16 resultados y 60 segundos. Un id desconocido, expiración, desalojo o no archivado se rechazan por motivos distintos.

run

ParámetroValor predeterminadoDescripción
cmd—Nombre del comando
args[]Matriz de argumentos
cwdDirectorio actualDirectorio de trabajo
format"json""json", "compact", "json-no-raw"
includeDifffalseIncluir cambios del sistema de archivos antes y después de la ejecución
select where sort_by limit array—Filtros y proyección
budget—Presupuesto de tokens
contract_version"stable"Si es "next", agrega metadatos review
evidence"none""rows", "fields". Calcula la ubicación en el texto original por campo
retainfalseArchiva el resultado en memoria para usarlo con herramientas posteriores

Si no se especifican contract_version, evidence, retain, budget, el formato de respuesta es el mismo que en versiones anteriores.

format: "compact" reduce tokens plegando resultados tipo lista con schema y rows.

{
  "schema": ["name", "type", "size_bytes"],
  "rows": [["src", "directory", 4096], ["main.ts", "file", 1200]]
}

run_paged

Se usa para comandos con salida grande, como ps aux, find, grep -r. stdout.parsed siempre es null y divide el texto original en líneas.

ParámetroValor predeterminadoDescripción
page0Número de página, comenzando desde 0
page_size100Líneas por página. El límite superior es max_page_size (predeterminado 1000)

El page_info de la respuesta contiene total_lines, has_next, cache ({ hit, age_ms }). El mismo comando reutiliza el resultado de la primera ejecución durante 30 segundos.

describe

Si se llama sin argumentos, devuelve version, allowed_commands, available_parsers, guard_summary, telemetry_enabled.

Si se especifica un comando como describe({ cmd: "git" }), devuelve solo la información de ese comando, dentro de 2KB.

  • policy: subcomandos, banderas y argumentos posicionales permitidos por las protecciones
  • parser: formato que lee el analizador y campos del resultado
  • alternatives: argumentos alternativos para argumentos no admitidos
  • examples: ejemplos de argumentos que superan las protecciones actuales

dry_run

Recibe cmd, args, cwd y devuelve solo el veredicto de las protecciones, sin ejecutar.

{ "would_pass": false, "reason": "command_not_allowed", "message": "Command 'rm' is not in the allowed list" }

El motivo del bloqueo es uno de: command_not_allowed, path_not_allowed, injection_pattern, arg_not_allowed.


Respuestas y manejo de errores

result.ok === true   ──▶ stdout.parsed 사용 (null이면 stdout.raw 사용)
result.ok === false  ──▶ result.failure.kind 로 분기
                           ├─ "guard"   가드가 차단함. 실행되지 않음
                           ├─ "exec"    실행 실패. message에 stderr
                           ├─ "parse"   파서 없음 (reason: "parser_not_found")
                           └─ "config"  필터 인자 오류 (unknown_field, type_mismatch)
{
  "ok": false,
  "failure": {
    "kind": "guard",
    "reason": "command_not_allowed",
    "message": "Command 'rm' is not in the allowed list"
  }
}

Por compatibilidad con versiones anteriores, el campo guard_error también se incluye, pero la ramificación se hace con failure.

Si el analizador se ejecutó pero no pudo producir un resultado, el motivo queda en stdout.parse_error y raw llega tal cual.

parse_error.reasonSignificado
parser_exceptionEl analizador lanzó una excepción
schema_violationFallo de validación de strict_schemas
unsupported_formatCombinación de argumentos que el analizador no maneja
unrecognized_outputHay líneas de datos pero no se leyó ningún valor

Argumentos no admitidos

Cada analizador declara el rango de argumentos que valida. Si se pasan argumentos fuera de ese rango, no se interpreta por conjetura y se devuelve unsupported_format; si existe un argumento que obtiene la misma información, se indica con hint.

{ "reason": "unsupported_format", "hint": { "args": ["log", "--format=%h %s"] } }
EntradaSugerencia
uname -r["-a"]
git status -s --ignored["status", "--ignored"]
kubectl get pods -o yaml["get", "pods", "-o", "json"]

Los comandos cuya salida ya es JSON (kubectl get pods -o json, docker inspect) entran directamente en parsed sin analizador.


Protecciones

Se aplican cuatro verificaciones en orden para evitar que comandos mal formados por el agente se ejecuten tal cual.

 cmd + args
     │
     ▼
 [1] allowed_commands   목록에 없는 명령          ──▶ command_not_allowed
     │
 [2] allowed_paths      cwd·경로 인자가 범위 밖    ──▶ path_not_allowed
     │
 [3] block_patterns     ; $( ` && || | > >> <     ──▶ injection_pattern
     │
 [4] arg restrictions   node -e, npx --yes 등      ──▶ arg_not_allowed
     │
     ▼
  실행
  1. Lista de comandos permitidos: los comandos que no estén en allowed_commands se rechazan sin crear el proceso.
  2. Restricción de rutas: si se configura allowed_paths, se verifican cwd y los argumentos que parecen rutas (los que contienen /, comienzan con . o ~, o son elementos que realmente existen, incluidos enlaces simbólicos). Si está vacío, no hay restricción de rutas.
  3. Patrones de inyección: si un argumento contiene metacaracteres de shell, se rechaza.
  4. Restricción de argumentos por comando: node -e, node --eval, node --input-type, npx --yes están bloqueados por defecto.

Las protecciones son una línea de defensa a nivel de proceso, no un sandbox del kernel. Para el aislamiento en entornos no confiables, consulta SECURITY.md.


Comandos admitidos

Hay analizadores predeterminados para 43 comandos. Los campos de resultado por comando se verifican con describe({ cmd: "…" }).

CategoríaComandoPermitido por defecto
Sistema de archivosls -l find stat du df treeO
Procesosps auxO
Redping curl -I netstat lsof -i ss digO
Textogrep -n wc head tail catO
Gitgit status git status --porcelain git log --oneline git diff git branch -vvO
Desplieguekubectl get docker gh pr list helm listO
Entornoenv pwd whichO
Sistemafree uname id systemctl list-units journalctl apt list apt search brew list --versionsO
Paquetesnpm listO
Paquetespnpm list yarn listRequiere permiso explícito (yarn también necesita el perfil build)
Compilaciónterraform plan cargo treePerfil build
Control de procesoskillRequiere permiso explícito
Windowsdir tasklist ipconfig systeminfoRequiere permiso explícito
  • Requiere permiso explícito: debes agregar el comando a guard.allowed_commands.
  • Perfil build: debes cambiar guard.profile a "build". cargo y yarn pueden ejecutar envoltorios o scripts especificados por el repositorio incluso para comandos de consulta, por lo que solo se habilitan en este perfil.

Funciones avanzadas

Filtros y proyección

El servidor filtra el arreglo de nivel superior del resultado del análisis (ls de entries, commits de git log, etc.) para recibir solo lo necesario.

 parsed rows ──▶ where ──▶ sort_by ──▶ limit ──▶ select ──▶ response
{
  "cmd": "ls", "args": ["-l"],
  "where":   [{ "field": "type", "op": "eq", "value": "file" },
              { "field": "size_bytes", "op": "gt", "value": 1000 }],
  "sort_by": { "field": "size_bytes", "order": "desc" },
  "limit":   10,
  "select":  ["name", "size_bytes"]
}
  • Operadores: eq ne prefix contains (cadena, número, booleano, null), gt gte lt lte (número). Todas las condiciones deben cumplirse.
  • Si hay varios arreglos, se elige el objetivo con array.
  • Al resultado se le agrega _summary: { total, matched, shown } y se omiten stdout.raw.
  • La ordenación es estable y las filas sin valor van al final.
  • En un directorio con 500 elementos, pasar select: ["name","size_bytes"], limit: 50 reduce el tamaño del resultado de 30 122 tokens a 725 tokens.

Presupuesto de tokens

Ajusta el resultado a un presupuesto de tokens determinado e informa qué se omitió y cuánto.

{ "max_tokens": 2000, "required_fields": ["path"], "overflow": "page" }
 Agent                              Parism
   │ run(cmd, budget, retain:true)    │
   │────────────────────────────────▶│ 실행, 파싱, 예산에 맞춰 자름
   │◀────────────────────────────────│ budget, omission[], continuation.cursor
   │                                  │
   │ fetch_result(result_id, cursor)  │
   │────────────────────────────────▶│ 보관본에서 다음 페이지 (재실행 없음)
   │◀────────────────────────────────│ 다음 행 + 새 cursor
   │          ... cursor가 없을 때까지 반복
"budget":   { "max_tokens": 2000, "measured_tokens": 1842, "budget_met": true },
"omission": [{ "stage": "budget", "rows_total": 206, "rows_returned": 138, "rows_omitted": 68 }]
  • El presupuesto determina cuánto del resultado ya obtenido se envía. No reduce el tiempo de ejecución ni la cantidad recopilada.
  • required_fields y los campos de identificación de fila nunca se omiten de ninguna fila. Si no se pueden mantener dentro del presupuesto, se devuelve un error en lugar de enviar solo una parte.
  • Si el presupuesto es menor que el tamaño mínimo de respuesta (aproximadamente 1200 tokens), se rechaza antes de ejecutar con budget_too_small.
  • omission[].stage es uno de capture, parse, projection, budget, privacy, por lo que se pueden distinguir las filas omitidas por presupuesto de las omitidas por problemas del analizador.
  • El tokenizador tiene dos modos: parism/approx (aproximado) y byte (por carácter). El alcance de la medición es solo el JSON generado por Parism y puede diferir del recuento interno de tokens del modelo.
  • El cursor está vinculado al resultado y a las condiciones de consulta. Un cursor de otro resultado se rechaza con cursor_mismatch y un cursor manipulado con cursor_invalid.

El JSON es más grande que el texto original con el mismo contenido. Para 200 líneas de ls -la, el texto original es de 5044 tokens y el JSON de 12 204 tokens. Si necesitas ahorrar tokens, usa select, limit, format: "json-no-raw", budget juntos.

Consulta de justificación

Responde "¿de dónde proviene este valor en el texto original?" con intervalos de bytes.

 run(cmd, { contract_version: "next", evidence: "fields", retain: true })
   └─▶ review.result_id
         │
 explain_result(result_id, pointer: "/processes/0/pid")
   └─▶ value, source_kind, source_spans [start, end), transform
{
  "ok": true, "result_id": "r_...", "pointer": "/processes/0/pid",
  "value": 1,
  "source_kind": "derived",
  "source_spans": [{ "source": "stdout", "start": 90, "end": 91, "line": 2, "transform": "parseInt" }],
  "transform": "parseInt", "age_ms": 12
}
  • Los intervalos son desplazamientos de bytes UTF-8 [start, end) basados en el texto original con secretos enmascarados.
  • Los valores idénticos al texto original son verbatim; los que pasaron por una transformación son derived e incluyen la transformación aplicada.
  • Los analizadores que generan justificación actualmente son ps y git status --porcelain. Los campos de otros analizadores son source_kind: "none" y el motivo queda en warnings.
  • La justificación solo indica qué generó el comando en ese momento; no es una prueba de que el valor sea verdadero.
  • Usar evidence o budget desactiva la transformación compact automática, porque en una tabla plegada el objetivo del puntero desaparece.

Los campos principales de review, que se agrega cuando es contract_version: "next", son los siguientes.

CampoSignificado
result_idid que se pasa a herramientas posteriores
parser_id / parser_version / schema_versionAnalizador y esquema que produjeron el resultado
content_hashHash del texto original
source_complete / parse_complete / representation_losslessSi la recopilación, el análisis y la transformación se completaron sin pérdidas (true / false / unknown)
privacy_transform"none" / "masked" / "unknown"
retainedSi está archivado
warningsMotivo de incompletitud o falta de justificación

Comparación de resultados

compare_results compara dos resultados archivados con run(retain: true).

 run(..., retain:true) ─▶ base_id ─┐
                                   ├─▶ compare_results(base_id, current_id)
 run(..., retain:true) ─▶ current_id ┘        │
                                              ├─ comparable: false ─▶ refusals.reasons
                                              └─ comparable: true  ─▶ added / removed / changed
{ "comparable": false, "refusals": { "reasons": ["different command"] } }
  • Argumentos opcionales: keys, ignore_fields, strict.
  • Si alguno de los dos está incompleto, las filas faltantes no se consideran eliminaciones; se ponen en espera en partial.withheld_reasons.
  • Criterio de identificación de filas: para git, la ruta real del repositorio y la ruta del archivo; para Kubernetes, context, namespace, kind y metadata.uid. Las salidas de tabla sin uid no se consideran el mismo recurso. ps se pone en espera porque los PID pueden reutilizarse.
  • Si el mismo identificador aparece dos veces, se detiene con duplicate_identity.
  • argv se compara por hash y en pantalla solo se muestran valores enmascarados. Las variables de entorno solo registran sus nombres.

Configuración

prism.config.json cambia el comportamiento de las protecciones y los analizadores.

 ~/.parism/prism.config.json      전역
           │  덮어씀
 <cwd>/prism.config.json          프로젝트 (가드를 넓히지 못함*)
           │  덮어씀
 PARISM_* 환경 변수
           ▼
     최종 설정

* Para ampliar las protecciones con configuración del proyecto, coloca "trust_project_config": true en la configuración global.

{
  "guard": {
    "allowed_commands": ["ls", "git", "find", "grep", "env", "ps"],
    "allowed_paths": ["/home/user/projects"],
    "profile": "readonly",
    "timeout_ms": 10000,
    "max_output_bytes": 102400,
    "max_items": 500,
    "default_page_size": 100,
    "block_patterns": [";", "$(", "`", "&&", "||", ">", ">>", "<", "|"],
    "command_arg_restrictions": {
      "node": { "blocked_flags": ["-e", "--eval", "-r", "--require", "-p", "--print", "--input-type"] },
      "npx":  { "blocked_flags": ["--yes", "-y"] }
    },
    "secrets": {
      "env_patterns": ["TOKEN", "SECRET", "AUTHZ", "PASSWORD", "PASSWD", "CREDENTIAL"],
      "output_redaction_enabled": false
    }
  },
  "parsers": {
    "strict_schemas": false,
    "external_isolation": "worker",
    "external_time_limit_ms": 500,
    "external_memory_limit_mb": 128
  },
  "telemetry": {
    "enabled": false
  }
}
ClaveDescripción
guard.allowed_pathsSi está vacío, no hay restricción de rutas
guard.profile"readonly" (predeterminado) solo permite subcomandos de consulta. "build" agrega comandos de compilación y prueba como npm run, npm test, cargo build, terraform plan, docker compose ps. Ejecuta código del proyecto, así que actívalo solo en repositorios de confianza
guard.command_arg_restrictionsSe combina con los valores predeterminados. Cambiar solo algunos comandos conserva el resto de las restricciones predeterminadas
guard.command_policiesSobrescribe las reglas de subcomandos y banderas por comando
guard.secrets.env_patternsElimina las variables de entorno con nombre coincidente de los procesos hijos
guard.secrets.output_redaction_enabledSi es true, reemplaza en la salida los valores que coinciden con output_patterns por [REDACTED]
guard.secrets.output_patternsSi se omite, usa los patrones predeterminados (tokens de GitHub, GitLab, AWS, Slack, etc.). Para desactivarlo, usa []
parsers.strict_schemasSi es true, valida el resultado del análisis con un esquema Zod
telemetry.enabledSi es true, agrega el tiempo por etapa a la respuesta y muestra estadísticas por comando en describe. No se envía a ningún destino externo

node, npx, yarn deben colocarse directamente en allowed_commands y solo funcionan en el perfil build. A npx se le agrega --no automáticamente.

Variables de entorno

Variable de entornoDestinoFormato
PARISM_ALLOWED_COMMANDSguard.allowed_commandsSeparado por comas
PARISM_ALLOWED_PATHSguard.allowed_pathsSeparado por comas
PARISM_TIMEOUT_MSguard.timeout_msEntero
PARISM_MAX_OUTPUT_BYTESguard.max_output_bytesEntero
PARISM_MAX_ITEMSguard.max_itemsEntero
PARISM_DEFAULT_PAGE_SIZEguard.default_page_sizeEntero
PARISM_STRICT_SCHEMASparsers.strict_schemastrue o 1
PARISM_ADAPTIVE_FORMAT_JSONparsers.adaptive_format_threshold.jsonEntero
PARISM_ADAPTIVE_FORMAT_COMPACTparsers.adaptive_format_threshold.compactEntero
PARISM_ADAPTIVE_FORMAT_JSON_NO_RAWparsers.adaptive_format_threshold.json_no_rawEntero
PARISM_TELEMETRY_ENABLEDtelemetry.enabledtrue o 1

Uso como biblioteca

Se puede llamar directamente desde código Node.js sin MCP.

import { createEngine } from "@nerdvana/parism/engine";

const engine = await createEngine();
const result = await engine.run("ls", { args: ["-la"] });
console.log(result.stdout.parsed);
  • createEngine() lee la misma capa de configuración que el servidor MCP y adjunta los parsers externos registrados. Para usar solo archivos específicos, usa createEngine({ configPath: "…" }).
  • Opción run: args, cwd, format, includeDiff, select, where, sort_by, limit, array, page, page_size.
  • Puedes ver la información de un solo comando con engine.describe("git").

Parser personalizado

Puedes adjuntar parsers directamente a comandos que no tienen un parser predeterminado. Parism es solo para ESM y el esquema usa zod 3.

npm install @nerdvana/parism zod@^3
# package.json 에 "type": "module" 필요
 capture ──▶ init-parser ──▶ 기대값 작성 ──▶ test ──▶ add ──▶ inspect
 (출력 저장)  (스캐폴드)     (사람이 검토)   (재생 검증) (등록)  (토큰 비교)
parism capture "htop -b -n 1"   # 1. 실제 출력을 fixture로 저장
parism init-parser htop          # 2. 파서 팩 스캐폴드 생성
# 3. fixture에 기대값과 reviewed_by를 직접 적는다
parism test ~/.parism/fixtures   # 4. 저장된 출력으로 파서를 다시 돌려 차이 확인
parism add ./htop                # 5. 등록. 재시작 없이 바로 사용
parism inspect "htop -b -n 1"    # 6. raw / parsed / compact 결과와 토큰 수 비교

Los paquetes registrados se guardan en ~/.parism/parsers/ y se cargan automáticamente al iniciar el servidor.

Interfaz ParserPack

import type { ParserPack } from "@nerdvana/parism/types";

const pack: ParserPack = {
  name: "my-command",
  parse(raw, args, ctx?) { /* 구조화된 결과 반환 */ },
  schema: { /* Zod 스키마 */ },
  fixtures: [{ input: "...", args: [], expected: { /* ... */ } }],
  acceptedFlags: { "-a": "bool", "-n": "value" }, // 선택: 검증한 플래그. 그 밖은 unsupported_format
  acceptedPositionals: { max: 1 },                // 선택: 위치 인자 규칙
  supports: (args) => args.length < 4,            // 선택: 추가 지원 조건
  headerLines: 1,                                 // 선택: 머리 줄 수
  noise: /^Total /,                               // 선택: 데이터가 아닌 줄
  rowsKey: "items",                               // 선택: 행 배열의 키
};

export default pack;

Fixtures y pruebas de regresión

$ parism capture "ls -l src"
Fixture saved: ~/.parism/fixtures/ls-20261005-163909.json

$ parism test ~/.parism/fixtures
fixture 4개
  검토된 기대값 1개 중 일치 0 · 변화 1
  미검토 기대값 3개 (사람이 검토해야 계약이 된다)
  매니페스트 오류 0개
  ...
  ls-20261005-163909  (ls)
  [parsed] 10건
    /entries/0/name  value  기대 "WRONG" → 실제 "cli"

Los valores esperados de los fixtures se escriben en el siguiente formato.

"expected": {
  "parsed": { "entries": [ … ] },
  "reviewed_by": "이름",
  "note": "이 값이 맞는 이유"
}
  • Al capturar, se ocultan secretos, rutas de inicio y valores de argumentos como --token=, y el registro de lo ocultado se deja en redactions.
  • Los valores esperados sin reviewed_by se tratan como sugerencias y no se cuentan como fallos.
  • La comparación es una coincidencia completa. Si solo escribes algunos campos en el valor esperado, el resto se reportará como extra, así que debes escribirlo con la misma forma que el resultado real del parseo.
  • parism test no vuelve a ejecutar el comando ni reescribe automáticamente los valores esperados.
  • Los valores esperados basados en razones solo verifican los punteros escritos. Si necesitas una coincidencia completa, usa evidence.exhaustive: true.

El formato del manifiesto está en SPECIFICATION.md §5.2.4.

parism eval

En este host, se verifica en tres capas si el comando se comporta como se espera.

CapaContenido de verificación
executionSi realmente se ejecutó. Distingue entre bloqueo por guardia (blocked) y fallo de ejecución
parseSi se leyó estructuralmente. Distingue entre falta de parser y fallo de parseo
taskSi cumplió la tarea. Una tarea que busca algo inexistente debe no encontrarlo para ser exitosa
parism eval                    # 전체 시나리오
parism eval execution-parse    # 시나리오 하나
parism eval --verbose          # 모든 항목 출력

Si hay al menos un elemento que difiere de lo esperado, el código de salida es 1. Los elementos sin valor esperado se excluyen del recuento.

Aislamiento de parsers externos

Los paquetes registrados se ejecutan en un hilo de trabajo separado por paquete (parsers.external_isolation: "worker").

  • Si una llamada supera external_time_limit_ms (500 ms por defecto), el trabajador muere, o el heap de V8 supera external_memory_limit_mb (128 MB por defecto), se reporta como parser_exception. Después, durante un tiempo de espera que aumenta desde 2 segundos hasta un máximo de 30 segundos, ese paquete responde con fallo inmediato y el servidor sigue funcionando.
  • El valor de retorno de parse() debe ser clonable estructuralmente. Si contiene funciones, Promises o Symbols, es parser_exception.
  • La salida de console dentro del paquete va a stderr.
  • El costo de clonación por llamada es de aproximadamente 0.1 ms para entradas de 20 líneas y aproximadamente 1.6 ms para entradas de 500 líneas.
  • Para ejecutar en el hilo principal, coloca "parsers": { "external_isolation": "none" } en la configuración global.

El aislamiento de trabajadores es aislamiento de fallos, no un sandbox de seguridad. El trabajador tiene los mismos permisos de archivos, red y variables de entorno que el servidor. Si necesitas usar paquetes no confiables, ejecuta Parism completo dentro de un contenedor o VM.

Comandos CLI

ComandoDescripción
parismEjecuta el servidor MCP (stdio)
parism capture "<command>"Refina el resultado de ejecución y lo guarda como fixture
parism init-parser <name>Genera el scaffold de un paquete de parser (parser.ts, schema.json, fixtures/)
parism test [dir]Reproduce fixtures sin conexión y reporta diferencias. Si hay fixtures rotos, código de salida 1
parism add <path>Registra el paquete de parser en ~/.parism/parsers/
parism inspect <command> [args...]Compara raw / parsed / compact y el número de tokens
parism eval [scenario]Evalúa el comportamiento del host en tres capas

Si pasas argumentos separados como parism inspect ls -l /path, se transmiten tal cual. Si los pasas como una sola cadena como parism inspect "ls -l /path", se dividen por espacios, por lo que las comillas y los espacios consecutivos no se conservan.


Al actualizar de 2.0.x a 2.1.0

Si solo llamas a run mediante MCP, no hay nada que cambiar. Los nombres de las herramientas siguen igual y se agregaron 3 herramientas (explain_result, fetch_result, compare_results). Solo necesitas ajustar código o configuración en los siguientes casos.

DestinoAntes2.1.0
Autores de ParserPack externoscontract.noise, rowLine, acceptedValues en el RegExp del hilo principalDescriptor calculado por el trabajador. Si necesitas el método anterior, usa parsers.external_isolation: "none"
Llamadores de toCompact(), parism inspectRetorno de unknownCompactOutcome ({ok:true,value} o {ok:false,reason,message})
Configuración que omite guard.secrets.output_patternsPatrón predeterminado no aplicadoPatrón predeterminado aplicado. Para desactivarlo, usa output_patterns: []
Usuarios de git status --porcelainDestinatarios de la guía de failure.hintFormato compatible. Se parsea como arreglo de entries
Código que guarda elementos porcelain tal cualxy, index, worktree, path, orig_pathCampo quoted agregado (solo tiene valor en modo línea)

El cambio del valor predeterminado de output_patterns es una corrección de seguridad. Antes, si omitías esta clave, incluso con el ocultamiento de salida activado, los tokens en forma de sk-, ghp_, AKIA, xoxb-, glpat- quedaban expuestos.


Alcance

  • Parism no reemplaza el shell. Ejecuta comandos existentes y convierte su salida en estructura.
  • Al consultar, continuar leyendo o comparar resultados archivados, no vuelve a ejecutar el comando. Los resultados vencidos deben ejecutarse de nuevo.
  • La comparación solo ocurre entre los dos resultados que proporciona el llamador. No se monitorea periódicamente.
  • El presupuesto de tokens se basa en el JSON creado por Parism. No se garantiza el número de tokens que el modelo realmente cuenta.

Hecho por Jinho Choi  |  Cómprame un café