Parism

Analisador estruturado de saída de shell para agentes de IA — servidor MCP

Documentação

Parism

Refract the Shell. Every command, structured.

한국어 | English

Um servidor MCP e biblioteca Node.js que permite que agentes de IA executem comandos de shell com segurança e recebam os resultados em JSON.

Documentação: SPECIFICATION · SECURITY · CHANGELOG


Visão geral

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 sempre contém a saída original, intacta.
  • parsed contém a estrutura lida pelo parser. Comandos sem parser retornam null.
  • Há parsers padrão para 43 comandos, e você pode adicionar parsers personalizados.

A saída do shell é feita para humanos. Se um agente tentar interpretá-la diretamente, frequentemente erra em espaços em nomes de arquivos, na ordem das colunas por SO (ps) e em cabeçalhos que variam por ambiente (df). O Parism detecta o SO, escolhe o parser correto e retorna o resultado interpretado.


Arquitetura

  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? }

Os comandos são executados diretamente como binários, sem passar pelo shell. Bloqueio, falha de execução e falha de parsing retornam respostas no mesmo formato, sem lançar exceções. O agente só precisa verificar failure.kind para decidir o próximo passo.


Início rápido

1. Instalação

npx @nerdvana/parism

Sem argumentos, executa como servidor MCP via stdio. Para compilar a partir do código-fonte:

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

2. Registrar no cliente MCP

A maioria dos clientes aceita o formato abaixo diretamente.

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

A localização das configurações por cliente está nos seguintes 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. Primeira sequência de chamadas do agente

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

Ferramentas

Ao conectar, 7 ferramentas são expostas.

FerramentaExecuta comandoFinalidade
runOExecução padrão. Inclui opções de filtro, orçamento e justificativa
run_pagedOLê saídas grandes em páginas de linhas
describeXVerifica ambiente, comandos permitidos e informações do parser
dry_runXVerifica antecipadamente se o guarda permitiria a execução
explain_resultXConsulta de onde um valor de um resultado arquivado veio no texto original
fetch_resultXLê a próxima página de um resultado truncado por orçamento
compare_resultsXCompara a diferença entre dois resultados arquivados

explain_result, fetch_result, compare_results apenas leem resultados arquivados e não reexecutam comandos. Os arquivos ficam apenas na memória do processo do servidor, com limite de 2MiB por resultado, 32MiB no total, máximo de 16 itens, por 60 segundos. IDs desconhecidos, expirados, removidos ou não arquivados são rejeitados com motivos distintos.

run

ParâmetroPadrãoDescrição
cmd—Nome do comando
args[]Array de argumentos
cwdDiretório atualDiretório de trabalho
format"json""json", "compact", "json-no-raw"
includeDifffalseInclui mudanças no sistema de arquivos antes e depois da execução
select where sort_by limit array—Filtros e projeção
budget—Orçamento de tokens
contract_version"stable"Se "next", adiciona metadados review
evidence"none""rows", "fields". Calcula a localização no texto original por campo
retainfalseArquiva o resultado na memória para uso por ferramentas subsequentes

Se contract_version, evidence, retain, budget não forem especificados, o formato da resposta permanece igual ao da versão anterior.

format: "compact" reduz tokens ao dobrar resultados em lista com schema e rows.

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

run_paged

Use para comandos com saída grande, como ps aux, find, grep -r. stdout.parsed é sempre null e divide o texto original em linhas.

ParâmetroPadrãoDescrição
page0Número da página, começando em 0
page_size100Linhas por página. Limite máximo: max_page_size (padrão 1000)

O campo page_info da resposta contém total_lines, has_next, cache ({ hit, age_ms }). O mesmo comando reutiliza o resultado da primeira execução por 30 segundos.

describe

Sem argumentos, retorna version, allowed_commands, available_parsers, guard_summary, telemetry_enabled.

Se um comando for especificado, como describe({ cmd: "git" }), retorna apenas as informações desse comando, em até 2KB.

  • policy: subcomandos, flags e argumentos posicionais permitidos pelo guarda
  • parser: formato lido pelo parser e campos do resultado
  • alternatives: argumentos alternativos para argumentos não suportados
  • examples: exemplos de argumentos que passam no guarda atual

dry_run

Recebe cmd, args, cwd e retorna apenas a decisão do guarda, sem executar.

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

O motivo do bloqueio é um dos seguintes: command_not_allowed, path_not_allowed, injection_pattern, arg_not_allowed.


Respostas e tratamento de falhas

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"
  }
}

Para compatibilidade com versões anteriores, o campo guard_error também é enviado, mas a ramificação deve ser feita com failure.

Se o parser foi executado mas não conseguiu produzir um resultado, o motivo fica em stdout.parse_error e raw permanece como está.

parse_error.reasonSignificado
parser_exceptionO parser lançou uma exceção
schema_violationFalha na validação de strict_schemas
unsupported_formatCombinação de argumentos não tratada pelo parser
unrecognized_outputHá linhas de dados, mas nenhum valor foi lido

Argumentos não suportados

Cada parser declara o intervalo de argumentos que valida. Se um argumento fora desse intervalo for fornecido, o parser não tenta adivinhar e retorna unsupported_format; se houver um argumento que obtenha a mesma informação, ele é indicado em hint.

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

Comandos cuja saída já é JSON (kubectl get pods -o json, docker inspect) vão direto para parsed, sem parser.


Guarda

Quatro verificações são aplicadas em sequência para impedir que comandos malformados criados pelo agente sejam executados.

 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: comandos que não estão em allowed_commands são rejeitados sem criar o processo.
  2. Restrição de caminho: se allowed_paths estiver definido, argumentos que parecem caminhos (contêm cwd, começam com / ou ., ~, ou que existem de fato, incluindo links simbólicos) são verificados. Se vazio, não há restrição de caminho.
  3. Padrões de injeção: argumentos com metacaracteres de shell são rejeitados.
  4. Restrições por comando: node -e, node --eval, node --input-type, npx --yes são bloqueados por padrão.

O guarda é uma defesa em nível de processo, não um sandbox de kernel. Para isolamento em ambientes não confiáveis, veja SECURITY.md.


Comandos suportados

43 comandos têm parser padrão. Os campos de resultado por comando podem ser verificados com describe({ cmd: "…" }).

CategoriaComandoPermitido por padrão
Sistema de arquivosls -l find stat du df treeO
Processosps auxO
Redeping 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
Implantaçãokubectl get docker gh pr list helm listO
Ambienteenv pwd whichO
Sistemafree uname id systemctl list-units journalctl apt list apt search brew list --versionsO
Pacotesnpm listO
Pacotespnpm list yarn listRequer permissão explícita (yarn também exige perfil build)
Buildterraform plan cargo treePerfil build
Controle de processoskillRequer permissão explícita
Windowsdir tasklist ipconfig systeminfoRequer permissão explícita
  • Requer permissão explícita: o comando deve ser adicionado a guard.allowed_commands.
  • Perfil build: guard.profile deve ser alterado para "build". cargo e yarn podem executar wrappers ou scripts definidos pelo repositório, mesmo sendo comandos de consulta, por isso só são liberados nesse perfil.

Recursos avançados

Filtros e projeção

O array de nível superior do resultado do parsing (ls de entries, git log de commits, etc.) é filtrado no servidor para receber apenas o necessário.

 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 (string, número, booleano, null), gt gte lt lte (número). Todas as condições devem ser atendidas.
  • Se houver vários arrays, use array para escolher o alvo.
  • O resultado recebe _summary: { total, matched, shown } e stdout.raw é removido.
  • A ordenação é estável; linhas sem valor vão para o final.
  • Em um diretório com 500 itens, usar select: ["name","size_bytes"], limit: 50 reduz o tamanho do resultado de 30.122 tokens para 725 tokens.

Orçamento de tokens

Ajusta o resultado ao orçamento definido e informa o que foi omitido e em que quantidade.

{ "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 }]
  • O orçamento define quanto do resultado já obtido será enviado. Não reduz o tempo de execução nem a quantidade coletada.
  • required_fields e os campos de identificação de linha nunca são omitidos de nenhuma linha. Se não for possível mantê-los dentro do orçamento, a resposta falha em vez de enviar parcialmente.
  • Se o orçamento for menor que o tamanho mínimo da resposta (cerca de 1.200 tokens), a solicitação é rejeitada antes da execução com budget_too_small.
  • omission[].stage é um dos seguintes: capture, parse, projection, budget, privacy, permitindo distinguir linhas omitidas por orçamento das omitidas por problema no parser.
  • O tokenizador tem dois modos: parism/approx (aproximado) e byte (por caractere). A medição cobre apenas o JSON gerado pelo Parism e pode diferir da contagem interna de tokens do modelo.
  • O cursor está vinculado ao resultado e às condições da consulta. Cursors de outros resultados são rejeitados com cursor_mismatch; cursors adulterados, com cursor_invalid.

JSON é maior que o texto original equivalente. Para ls -la com 200 linhas, o texto original tem 5.044 tokens e o JSON, 12.204. Para economizar tokens, use select, limit, format: "json-no-raw", budget juntos.

Consulta de justificativa

Responde "de onde veio esse valor no texto original" com 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
}
  • Os intervalos são offsets UTF-8 em bytes sobre o texto original com segredos mascarados, no formato [start, end).
  • Valores idênticos ao original usam verbatim; valores transformados usam derived, com a transformação aplicada.
  • Os parsers que geram justificativa atualmente são ps e git status --porcelain. Campos de outros parsers retornam source_kind: "none", com o motivo em warnings.
  • A justificativa indica apenas o que o comando exibiu naquele momento; não é prova de que o valor é verdadeiro.
  • Usar evidence ou budget desativa a transformação compact automática, pois em tabelas dobradas o alvo do ponteiro desaparece.

Os principais campos de review, presente quando contract_version: "next", são:

CampoSignificado
result_idID passado para ferramentas subsequentes
parser_id / parser_version / schema_versionParser e schema que geraram o resultado
content_hashHash do texto original
source_complete / parse_complete / representation_losslessSe coleta, parsing e transformação terminaram sem perdas (true / false / unknown)
privacy_transform"none" / "masked" / "unknown"
retainedSe está arquivado
warningsMotivo de incompletude ou ausência de justificativa

Comparação de resultados

compare_results compara dois resultados arquivados com 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 opcionais: keys, ignore_fields, strict.
  • Se um dos lados estiver incompleto, linhas ausentes não são tratadas como remoção; ficam pendentes em partial.withheld_reasons.
  • Critério de identificação de linha: para git, caminho real do repositório e caminho do arquivo; para Kubernetes, context, namespace, kind e metadata.uid. Saídas de tabela sem uid não são consideradas o mesmo recurso. ps fica pendente porque PIDs podem ser reutilizados.
  • Se o mesmo identificador aparecer duas vezes, a comparação para com duplicate_identity.
  • argv é comparado por hash e apenas valores mascarados são exibidos. Variáveis de ambiente são registradas apenas pelo nome.

Configuração

prism.config.json altera o comportamento do guarda e dos parsers.

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

* Para ampliar o guarda com configuração de projeto, defina "trust_project_config": true na configuração 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
  }
}
ChaveDescrição
guard.allowed_pathsSe vazio, não há restrição de caminho
guard.profile"readonly" (padrão) permite apenas subcomandos de consulta. "build" adiciona comandos de build e teste, como npm run, npm test, cargo build, terraform plan, docker compose ps. Como executam código do projeto, ative apenas em repositórios confiáveis
guard.command_arg_restrictionsMesclado com o padrão. Alterar apenas alguns comandos mantém as demais restrições padrão
guard.command_policiesSubstitui regras de subcomandos e flags por comando
guard.secrets.env_patternsRemove variáveis de ambiente com nome correspondente nos processos filhos
guard.secrets.output_redaction_enabledSe true, substitui valores que correspondem a output_patterns na saída por [REDACTED]
guard.secrets.output_patternsSe omitido, usa padrões padrão (tokens do GitHub, GitLab, AWS, Slack etc.). Para desativar, use []
parsers.strict_schemasSe true, valida o resultado do parsing com schema Zod
telemetry.enabledSe true, adiciona o tempo por etapa na resposta e mostra estatísticas por comando em describe. Não é enviado externamente

node, npx, yarn devem ser adicionados diretamente em allowed_commands e só funcionam no perfil build. npx recebe --no automaticamente.

Variáveis de ambiente

Variável de ambienteAlvoFormato
PARISM_ALLOWED_COMMANDSguard.allowed_commandsSeparado por vírgulas
PARISM_ALLOWED_PATHSguard.allowed_pathsSeparado por vírgulas
PARISM_TIMEOUT_MSguard.timeout_msInteiro
PARISM_MAX_OUTPUT_BYTESguard.max_output_bytesInteiro
PARISM_MAX_ITEMSguard.max_itemsInteiro
PARISM_DEFAULT_PAGE_SIZEguard.default_page_sizeInteiro
PARISM_STRICT_SCHEMASparsers.strict_schemastrue ou 1
PARISM_ADAPTIVE_FORMAT_JSONparsers.adaptive_format_threshold.jsonInteiro
PARISM_ADAPTIVE_FORMAT_COMPACTparsers.adaptive_format_threshold.compactInteiro
PARISM_ADAPTIVE_FORMAT_JSON_NO_RAWparsers.adaptive_format_threshold.json_no_rawInteiro
PARISM_TELEMETRY_ENABLEDtelemetry.enabledtrue ou 1

Uso como biblioteca

Pode ser chamado diretamente do código Node.js, sem 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() lê a mesma camada de configuração que o servidor MCP e anexa os parsers externos registrados. Para usar apenas arquivos específicos, use createEngine({ configPath: "…" }).
  • Opção run: args, cwd, format, includeDiff, select, where, sort_by, limit, array, page, page_size.
  • Use engine.describe("git") para ver informações de um único comando.

Parser personalizado

Você pode anexar parsers diretamente a comandos que não possuem parser padrão. Parism é exclusivo para ESM e o 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 결과와 토큰 수 비교

Os pacotes registrados são armazenados em ~/.parism/parsers/ e carregados automaticamente na inicialização do servidor.

Interface 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;

Fixture e verificação de regressão

$ 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"

Os valores esperados do fixture devem ser escritos no seguinte formato:

"expected": {
  "parsed": { "entries": [ … ] },
  "reviewed_by": "이름",
  "note": "이 값이 맞는 이유"
}
  • Ao capturar, segredos, caminhos domésticos e valores de argumentos como --token= são mascarados, e o histórico de mascaramento é registrado em redactions.
  • Valores esperados sem reviewed_by são tratados como sugestões e não contam como falhas.
  • A comparação é uma correspondência completa. Se você escrever apenas alguns campos nos valores esperados, todos os demais serão reportados como extra, portanto escreva no mesmo formato do resultado real da análise.
  • parism test não reexecuta o comando nem reescreve automaticamente os valores esperados.
  • Valores esperados baseados em evidências verificam apenas os ponteiros fornecidos. Se precisar de correspondência completa, use evidence.exhaustive: true.

O formato do manifesto está em SPECIFICATION.md §5.2.4.

parism eval

Neste host, verifica-se se o comando se comporta conforme o esperado em três camadas.

CamadaO que verifica
executionSe foi realmente executado. Distingue bloqueio por guarda (blocked) de falha de execução
parseSe foi lido estruturalmente. Distingue ausência de parser de falha de parsing
taskSe cumpriu a tarefa. Tarefas que buscam algo inexistente só são bem-sucedidas se não encontrarem
parism eval                    # 전체 시나리오
parism eval execution-parse    # 시나리오 하나
parism eval --verbose          # 모든 항목 출력

Se houver qualquer item diferente do esperado, o código de saída é 1. Itens sem valor esperado são excluídos da agregação.

Isolamento de parsers externos

Os pacotes registrados são executados em threads de worker separados por pacote (parsers.external_isolation: "worker").

  • Se uma chamada exceder external_time_limit_ms (padrão 500ms), se o worker morrer ou se o heap V8 exceder external_memory_limit_mb (padrão 128MB), isso é reportado como parser_exception. Depois disso, durante um tempo de espera que aumenta de 2 segundos até no máximo 30 segundos, o pacote responde com falha imediata, e o servidor continua operando.
  • O valor de retorno de parse() deve ser clonável estruturalmente. Se contiver funções, Promises ou Symbols, é parser_exception.
  • A saída de console dentro do pacote vai para stderr.
  • O custo de clonagem por chamada é de aproximadamente 0,1ms para entrada de 20 linhas e aproximadamente 1,6ms para entrada de 500 linhas.
  • Para executar na thread principal, defina "parsers": { "external_isolation": "none" } na configuração global.

O isolamento por worker é isolamento de falha, não um sandbox de segurança. O worker tem os mesmos arquivos, rede e permissões de variáveis de ambiente que o servidor. Se precisar usar pacotes não confiáveis, execute todo o Parism dentro de um contêiner ou VM.

Comandos CLI

ComandoDescrição
parismExecuta o servidor MCP (stdio)
parism capture "<command>"Refina o resultado da execução e salva como fixture
parism init-parser <name>Gera scaffold de pacote de parser (parser.ts, schema.json, fixtures/)
parism test [dir]Reproduz fixtures offline e reporta diferenças. Se houver fixtures quebrados, código de saída 1
parism add <path>Registra o pacote de parser em ~/.parism/parsers/
parism inspect <command> [args...]Comparação raw / parsed / compact e contagem de tokens
parism eval [scenario]Avalia o comportamento do host em três camadas

Se você dividir os argumentos como parism inspect ls -l /path, eles são passados diretamente. Se fornecidos como uma única string como parism inspect "ls -l /path", eles são divididos por espaços, portanto aspas e espaços consecutivos não são preservados.


Ao atualizar de 2.0.x para 2.1.0

Se você chamar apenas run via MCP, não há nada para mudar. Os nomes das ferramentas permanecem os mesmos e três ferramentas (explain_result, fetch_result, compare_results) foram adicionadas. Apenas nos casos abaixo você precisa ajustar código ou configuração.

AlvoAntes2.1.0
Autores de ParserPack externocontract.noise, rowLine, acceptedValues na thread principal RegExpDescritores calculados pelo worker. Se precisar do método antigo, use parsers.external_isolation: "none"
Chamadores de toCompact(), parism inspectRetorno de unknownCompactOutcome ({ok:true,value} ou {ok:false,reason,message})
Configuração omitindo guard.secrets.output_patternsPadrão não aplicadoPadrão aplicado. Para desativar, use output_patterns: []
Usuários de git status --porcelainAlvo de aviso de failure.hintFormato suportado. Parse como array de entries
Código que salva itens porcelain diretamentexy, index, worktree, path, orig_pathCampo quoted adicionado (só tem valor no modo linha)

A mudança do valor padrão de output_patterns é uma correção de segurança. Antes, se essa chave fosse omitida, mesmo com o mascaramento de saída ativado, tokens nas formas sk-, ghp_, AKIA, xoxb-, glpat- eram expostos diretamente.


Escopo

  • Parism não substitui o shell. Ele executa comandos existentes e transforma a saída em estrutura.
  • Ao consultar, retomar leitura ou comparar resultados arquivados, os comandos não são reexecutados. Resultados expirados precisam ser reexecutados.
  • A comparação ocorre apenas entre dois resultados fornecidos pelo chamador. Não há monitoramento periódico.
  • O orçamento de tokens é baseado no JSON criado pelo Parism. Não garante a contagem real de tokens feita pelo modelo.

Feito por Jinho Choi  |  Me pague um café