Parism
Analizador estructurado de salida de shell para agentes de IA — servidor MCP
Documentación
Parism
Refract the Shell. Every command, structured.
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"
}
]
}
}
}
rawsiempre contiene la salida original sin modificar.parsedcontiene la estructura que el analizador extrajo. Para comandos sin analizador, esnull.- 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.
| Cliente | Documento |
|---|---|
| Claude Desktop | claude-desktop.md |
| Claude Code | claude-code.md |
| Cursor | cursor.md |
| Gemini CLI | gemini-cli.md |
| Codex CLI | codex.md |
| GitHub Copilot CLI | copilot-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.
| Herramienta | Ejecuta comandos | Propósito |
|---|---|---|
run | O | Ejecución básica. Incluye opciones de filtro, presupuesto y justificación |
run_paged | O | Leer salidas grandes en páginas por líneas |
describe | X | Verificar entorno, comandos permitidos e información del analizador |
dry_run | X | Verificar de antemano si se superan las protecciones |
explain_result | X | Consultar de dónde proviene un valor en el texto original de un resultado archivado |
fetch_result | X | Leer la siguiente página de un resultado truncado por presupuesto |
compare_results | X | Comparar 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ámetro | Valor predeterminado | Descripción |
|---|---|---|
cmd | — | Nombre del comando |
args | [] | Matriz de argumentos |
cwd | Directorio actual | Directorio de trabajo |
format | "json" | "json", "compact", "json-no-raw" |
includeDiff | false | Incluir 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 |
retain | false | Archiva 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ámetro | Valor predeterminado | Descripción |
|---|---|---|
page | 0 | Número de página, comenzando desde 0 |
page_size | 100 | Lí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 proteccionesparser: formato que lee el analizador y campos del resultadoalternatives: argumentos alternativos para argumentos no admitidosexamples: 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.reason | Significado |
|---|---|
parser_exception | El analizador lanzó una excepción |
schema_violation | Fallo de validación de strict_schemas |
unsupported_format | Combinación de argumentos que el analizador no maneja |
unrecognized_output | Hay 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"] } }
| Entrada | Sugerencia |
|---|---|
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
│
▼
실행
- Lista de comandos permitidos: los comandos que no estén en
allowed_commandsse rechazan sin crear el proceso. - Restricción de rutas: si se configura
allowed_paths, se verificancwdy 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. - Patrones de inyección: si un argumento contiene metacaracteres de shell, se rechaza.
- Restricción de argumentos por comando:
node -e,node --eval,node --input-type,npx --yesestá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ía | Comando | Permitido por defecto |
|---|---|---|
| Sistema de archivos | ls -l find stat du df tree | O |
| Procesos | ps aux | O |
| Red | ping curl -I netstat lsof -i ss dig | O |
| Texto | grep -n wc head tail cat | O |
| Git | git status git status --porcelain git log --oneline git diff git branch -vv | O |
| Despliegue | kubectl get docker gh pr list helm list | O |
| Entorno | env pwd which | O |
| Sistema | free uname id systemctl list-units journalctl apt list apt search brew list --versions | O |
| Paquetes | npm list | O |
| Paquetes | pnpm list yarn list | Requiere permiso explícito (yarn también necesita el perfil build) |
| Compilación | terraform plan cargo tree | Perfil build |
| Control de procesos | kill | Requiere permiso explícito |
| Windows | dir tasklist ipconfig systeminfo | Requiere permiso explícito |
- Requiere permiso explícito: debes agregar el comando a
guard.allowed_commands. - Perfil build: debes cambiar
guard.profilea"build".cargoyyarnpueden 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:
eqneprefixcontains(cadena, número, booleano,null),gtgteltlte(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 omitenstdout.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: 50reduce 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_fieldsy 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[].stagees uno decapture,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) ybyte(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_mismatchy un cursor manipulado concursor_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 sonderivede incluyen la transformación aplicada. - Los analizadores que generan justificación actualmente son
psygit status --porcelain. Los campos de otros analizadores sonsource_kind: "none"y el motivo queda enwarnings. - La justificación solo indica qué generó el comando en ese momento; no es una prueba de que el valor sea verdadero.
- Usar
evidenceobudgetdesactiva 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.
| Campo | Significado |
|---|---|
result_id | id que se pasa a herramientas posteriores |
parser_id / parser_version / schema_version | Analizador y esquema que produjeron el resultado |
content_hash | Hash del texto original |
source_complete / parse_complete / representation_lossless | Si la recopilación, el análisis y la transformación se completaron sin pérdidas (true / false / unknown) |
privacy_transform | "none" / "masked" / "unknown" |
retained | Si está archivado |
warnings | Motivo 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.psse 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
}
}
| Clave | Descripción |
|---|---|
guard.allowed_paths | Si 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_restrictions | Se combina con los valores predeterminados. Cambiar solo algunos comandos conserva el resto de las restricciones predeterminadas |
guard.command_policies | Sobrescribe las reglas de subcomandos y banderas por comando |
guard.secrets.env_patterns | Elimina las variables de entorno con nombre coincidente de los procesos hijos |
guard.secrets.output_redaction_enabled | Si es true, reemplaza en la salida los valores que coinciden con output_patterns por [REDACTED] |
guard.secrets.output_patterns | Si se omite, usa los patrones predeterminados (tokens de GitHub, GitLab, AWS, Slack, etc.). Para desactivarlo, usa [] |
parsers.strict_schemas | Si es true, valida el resultado del análisis con un esquema Zod |
telemetry.enabled | Si 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 entorno | Destino | Formato |
|---|---|---|
PARISM_ALLOWED_COMMANDS | guard.allowed_commands | Separado por comas |
PARISM_ALLOWED_PATHS | guard.allowed_paths | Separado por comas |
PARISM_TIMEOUT_MS | guard.timeout_ms | Entero |
PARISM_MAX_OUTPUT_BYTES | guard.max_output_bytes | Entero |
PARISM_MAX_ITEMS | guard.max_items | Entero |
PARISM_DEFAULT_PAGE_SIZE | guard.default_page_size | Entero |
PARISM_STRICT_SCHEMAS | parsers.strict_schemas | true o 1 |
PARISM_ADAPTIVE_FORMAT_JSON | parsers.adaptive_format_threshold.json | Entero |
PARISM_ADAPTIVE_FORMAT_COMPACT | parsers.adaptive_format_threshold.compact | Entero |
PARISM_ADAPTIVE_FORMAT_JSON_NO_RAW | parsers.adaptive_format_threshold.json_no_raw | Entero |
PARISM_TELEMETRY_ENABLED | telemetry.enabled | true 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, usacreateEngine({ 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 enredactions. - Los valores esperados sin
reviewed_byse 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 testno 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.
| Capa | Contenido de verificación |
|---|---|
execution | Si realmente se ejecutó. Distingue entre bloqueo por guardia (blocked) y fallo de ejecución |
parse | Si se leyó estructuralmente. Distingue entre falta de parser y fallo de parseo |
task | Si 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 superaexternal_memory_limit_mb(128 MB por defecto), se reporta comoparser_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, esparser_exception. - La salida de
consoledentro 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
| Comando | Descripción |
|---|---|
parism | Ejecuta 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.
| Destino | Antes | 2.1.0 |
|---|---|---|
| Autores de ParserPack externos | contract.noise, rowLine, acceptedValues en el RegExp del hilo principal | Descriptor calculado por el trabajador. Si necesitas el método anterior, usa parsers.external_isolation: "none" |
Llamadores de toCompact(), parism inspect | Retorno de unknown | CompactOutcome ({ok:true,value} o {ok:false,reason,message}) |
Configuración que omite guard.secrets.output_patterns | Patrón predeterminado no aplicado | Patrón predeterminado aplicado. Para desactivarlo, usa output_patterns: [] |
Usuarios de git status --porcelain | Destinatarios de la guía de failure.hint | Formato compatible. Se parsea como arreglo de entries |
| Código que guarda elementos porcelain tal cual | xy, index, worktree, path, orig_path | Campo 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é