Labsco
JinHo-von-Choi logo

Parism

โ˜… 10

from JinHo-von-Choi

Structured shell output parser for AI agents โ€” MCP server

๐Ÿ”ฅ๐Ÿ”ฅ๐Ÿ”ฅโœ“ VerifiedFreeQuick setup

Parism

Refract the Shell. Every command, structured.

AI ์—์ด์ „ํŠธ๋ฅผ ์œ„ํ•œ ์•ˆ์ „ํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ OS ์‹คํ–‰ ๊ฒŒ์ดํŠธ์›จ์ด.

ํ•œ๊ตญ์–ด | English

๋ฌธ์„œ: README ยท SPECIFICATION ยท SECURITY ยท CHANGELOG

์„ค๊ณ„ ๊ฒฐ์ •, ๋ฒ„์ „ ์ด๋ ฅ, ๋ชจ๋“ˆ ๊ตฌ์กฐ์˜ ๋‹จ์ผ ๊ถŒ์œ„ ๋ฌธ์„œ: SPECIFICATION.md


์…ธ์€ ๋‹น์‹ ์„ ์œ„ํ•ด ์„ค๊ณ„๋˜์ง€ ์•Š์•˜๋‹ค

1969๋…„ Ken Thompson์ด Unix๋ฅผ ๋งŒ๋“ค ๋•Œ, ๊ทธ๋Š” ์ถœ๋ ฅ ๋Œ€์ƒ์ด ์‚ฌ๋žŒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ–ˆ๋‹ค. ์ •ํ™•ํžˆ ๋งํ•˜๋ฉด ํ„ฐ๋ฏธ๋„ ์•ž์— ์•‰์•„ ์žˆ๋Š”, ๋ˆˆ์ด ๋‹ฌ๋ฆฐ ์ƒ๋ฌผ.

๋ฐ˜์„ธ๊ธฐ๊ฐ€ ์ง€๋‚ฌ๋‹ค. ์ด์ œ ํ„ฐ๋ฏธ๋„์„ ์ฝ๋Š” ๊ฒƒ์€ ์‚ฌ๋žŒ๋งŒ์ด ์•„๋‹ˆ๋‹ค.

AI ์—์ด์ „ํŠธ๋Š” ls -la๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ ์ถœ๋ ฅ์„ ๋ฐ›๋Š”๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฑฐ๊ธฐ์„œ ์ง„์งœ ์ž‘์—…์ด ์‹œ์ž‘๋œ๋‹ค. ๊ณต๋ฐฑ์„ ๊ธฐ์ค€์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ , ์ฒซ ๋ฒˆ์งธ ์—ด์ด ๊ถŒํ•œ์ด๊ณ , ์„ธ ๋ฒˆ์งธ๊ฐ€ ์†Œ์œ ์ž์ด๊ณ , ํŒŒ์ผ๋ช…์ด ์–ด๋””์„œ ์‹œ์ž‘ํ•˜๋Š”์ง€๋ฅผ ํ† ํฐ์„ ํƒœ์›Œ๊ฐ€๋ฉฐ ์ถ”๋ก ํ•œ๋‹ค. ์ธ๊ฐ„์˜ ๋ˆˆ์ด 0.1์ดˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„.

์ด๊ฒƒ์€ ๋ฒˆ์—ญ์ด ์•„๋‹ˆ๋‹ค. ์•”ํ˜ธํ™”๋œ ์ ๋„ ์—†๋Š” ๋ฉ”์‹œ์ง€๋ฅผ ํ•ด๋…ํ•˜๋Š” ์ผ์ด๋‹ค.


์™œ ๋ฌธ์ œ์ธ๊ฐ€

์„ธ ๋ฒˆ์˜ ๋ฒˆ์—ญ์ด ์ผ์–ด๋‚œ๋‹ค.

์ฒซ ๋ฒˆ์งธ: ์ปค๋„์ด ํŒŒ์ผ์‹œ์Šคํ…œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ stat ๊ตฌ์กฐ์ฒด๋กœ ๊ด€๋ฆฌํ•œ๋‹ค. inode, mode, uid, gid, size, mtime. ์ด๋ฏธ ์™„๋ฒฝํ•˜๊ฒŒ ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋‹ค.

๋‘ ๋ฒˆ์งธ: ls๊ฐ€ ๊ทธ ๊ตฌ์กฐ๋ฅผ ์ธ๊ฐ„์ด ์ฝ๊ธฐ ์ข‹์€ ํ…์ŠคํŠธ๋กœ ํ‰ํƒ„ํ™”ํ•œ๋‹ค. drwxr-xr-x 2 user group 4096 Mar 06 09:23 src. ๊ตฌ์กฐ๊ฐ€ ํ…์ŠคํŠธ๋กœ ๋ฌด๋„ˆ์ง„๋‹ค.

์„ธ ๋ฒˆ์งธ: ์—์ด์ „ํŠธ๊ฐ€ ๊ทธ ํ…์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ๊ตฌ์กฐ๋กœ ๋˜๋Œ๋ฆฌ๋ ค ํ•œ๋‹ค. ๋ฌด๋„ˆ์ง„ ๊ฒƒ์„ ๋‹ค์‹œ ์„ธ์šฐ๋Š” ์ž‘์—…์ด๋‹ค.

Parism์ด ๊ฐœ์ž…ํ•˜๋Š” ๊ฒƒ์€ ๋‘ ๋ฒˆ์งธ์™€ ์„ธ ๋ฒˆ์งธ ์‚ฌ์ด๋‹ค. ํ•œ ๋ฒˆ ๋ฒ„๋ ค์ง„ ๊ตฌ์กฐ๋ฅผ ๋˜์ฐพ๋Š” ๊ฒƒ์ด๋‹ค.

์ด๊ฒƒ์ด ๋น„์šฉ์ด๋‹ค. ls ํ•œ ๋ฒˆ ์‹คํ–‰ํ•˜๊ณ  ํŒŒ์ผ ๋ชฉ๋ก์„ ์–ป๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ์—์ด์ „ํŠธ๊ฐ€ ์ถœ๋ ฅ์„ ํŒŒ์‹ฑํ•˜๋Š” ๋ฐ ์ˆ˜์‹ญ ๋ฒˆ์˜ ์ถ”๋ก  ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นœ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ข…์ข… ํ‹€๋ฆฐ๋‹ค. ๊ฒฝ๊ณ„ ์ผ€์ด์Šค, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ณต๋ฐฑ, OS๋ณ„๋กœ ๋ฏธ๋ฌ˜ํ•˜๊ฒŒ ๋‹ค๋ฅธ ์ถœ๋ ฅ ํ˜•์‹. ํ‹€๋ฆฌ๋ฉด ์žฌ์‹œ๋„ํ•œ๋‹ค. ์žฌ์‹œ๋„๋Š” ๋‹ค์‹œ ํ† ํฐ์ด๋‹ค.


์†”์งํ•œ ์ด์•ผ๊ธฐ โ€” ํ† ํฐ์€ ๋” ๋“ ๋‹ค

Parism์„ ๋งŒ๋“ค ๋•Œ ๊ธฐ๋Œ€ํ•œ ๊ฒƒ์€ ํ† ํฐ ์ ˆ์•ฝ์ด์—ˆ๋‹ค. ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๊ฐ€ raw ํ…์ŠคํŠธ๋ณด๋‹ค ํšจ์œจ์ ์ผ ๊ฒƒ์ด๋ผ๊ณ .

17๊ฐœ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ฒค์น˜๋งˆํฌํ•œ ๊ฒฐ๊ณผ๋Š” ๊ทธ ๊ธฐ๋Œ€๋ฅผ ์ •๋ฉด์œผ๋กœ ๋ฐฐ๋ฐ˜ํ–ˆ๋‹ค. JSON ์ถœ๋ ฅ์€ raw ํ…์ŠคํŠธ๋ณด๋‹ค ํ‰๊ท  205% ๋” ๋ฌด๊ฒ๋‹ค. ls -la 200๊ฐœ ํŒŒ์ผ ๊ธฐ์ค€์œผ๋กœ raw 5,807 ํ† ํฐ, Parism 15,531 ํ† ํฐ. ๊ฑฐ์˜ ์„ธ ๋ฐฐ๋‹ค. ํ‚ค ์ด๋ฆ„์ด ๋งค ํ•ญ๋ชฉ๋งˆ๋‹ค ๋ฐ˜๋ณต๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ธ๊ฐ„์˜ ๋ˆˆ์— ํ…Œ์ด๋ธ” ํ—ค๋” ํ•œ ์ค„์ด๋ฉด ๋˜๋Š” ์ •๋ณด๋ฅผ N๋ฒˆ ์จ์•ผ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๊ฐ™์€ ๋ฒค์น˜๋งˆํฌ๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ์‹ค ํ•˜๋‚˜๋ฅผ ๋“œ๋Ÿฌ๋ƒˆ๋‹ค. ์—์ด์ „ํŠธ๊ฐ€ raw ํ…์ŠคํŠธ๋ฅผ ์ง์ ‘ ํŒŒ์‹ฑํ•  ๋•Œ ์˜ค๋…๋ฅ ์ด ํ‰๊ท  4.18%, ๊ณต๋ฐฑ์ด ์„ž์ธ ํŒŒ์ผ๋ช…์—์„œ๋Š” 28.6%์— ๋‹ฌํ–ˆ๋‹ค. ์—ด ๋ฒˆ ์ค‘ ์„ธ ๋ฒˆ์€ ํ‹€๋ฆฐ๋‹ค. ํ‹€๋ฆฐ ๊ฒฐ๊ณผ๋กœ ์—์ด์ „ํŠธ๊ฐ€ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๊ทธ ์ž‘์—…์ด ๋˜ ํ‹€๋ฆฌ๊ณ , ๊ฒฐ๊ตญ ์‚ฌ๋žŒ์ด ๊ฐœ์ž…ํ•ด์„œ ๋˜๋Œ๋ฆฐ๋‹ค. ์žฌ์‹œ๋„ ํ† ํฐ, ๋””๋ฒ„๊น… ์‹œ๊ฐ„, ๋กค๋ฐฑ ๋น„์šฉ. ๋ณด์ด์ง€ ์•Š๋Š” ๊ณณ์—์„œ ๋น„์šฉ์ด ๋ถˆ์–ด๋‚œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ™์€ ๋ฒค์น˜๋งˆํฌ๊ฐ€ ํ•œ ๊ฐ€์ง€ ๋” ๋ณด์—ฌ์ค€ ๊ฒƒ์ด ์žˆ๋‹ค. "AIํ•œํ…Œ ์„ค๋ช…ํ•˜๋Š” ํ† ํฐ"์˜ ์†Œ๋ฉธ์ด๋‹ค. raw ํ…์ŠคํŠธ๋ฅผ ์ฃผ๋ฉด ์—์ด์ „ํŠธ์—๊ฒŒ "์ด ์ถœ๋ ฅ์€ ์ด๋Ÿฐ ํ˜•์‹์ด๊ณ , ์ฒซ ๋ฒˆ์งธ ์—ด์ด ๊ถŒํ•œ์ด๊ณ , ์„ธ ๋ฒˆ์งธ๊ฐ€ ์†Œ์œ ์ž์•ผ"๋ผ๊ณ  ์•Œ๋ ค์ค˜์•ผ ํ•œ๋‹ค. ๊ทธ ์ปจํ…์ŠคํŠธ ํ”„๋กฌํ”„ํŠธ๊ฐ€ Parism์„ ์“ฐ๋ฉด ํ‰๊ท  61% ์ค„์–ด๋“ ๋‹ค. JSON์ด ์Šค์Šค๋กœ ์ž๊ธฐ ๊ตฌ์กฐ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์—์ด์ „ํŠธ๋Š” ํ‚ค๋ฅผ ์ฝ์œผ๋ฉด ๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ญ์ „์ด ์ผ์–ด๋‚˜๋Š” ์ง€์ ์ด ์žˆ๋‹ค. ๋‹จ๋ฐœ์„ฑ ์กฐํšŒ โ€” ls ํ•œ ๋ฒˆ ์น˜๊ณ  ๋๋‚˜๋Š” ์ž‘์—… โ€” ์—์„œ๋Š” Parism์ด ํ† ํฐ์„ ๋” ๋จน๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์—์ด์ „ํŠธ๊ฐ€ ๋‹ค์Œ ์ž‘์—…์— ์‚ฌ์šฉํ•˜๋Š” ์ˆœ๊ฐ„, ๋น„์šฉ ๊ตฌ์กฐ๊ฐ€ ๋’ค์ง‘ํžŒ๋‹ค. raw๋ฅผ ์ž˜๋ชป ์ฝ์€ ์—์ด์ „ํŠธ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ๋กœ์— ํŒŒ์ผ์„ ์“ฐ๊ณ , ๊ทธ ์˜ค๋ฅ˜๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋А๋ผ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋’ค์ง€๊ณ , ์žฌ์‹œ๋„ํ•˜๊ณ , ๋˜ ํ‹€๋ฆฌ๋Š” ์ˆœํ™˜์ด ์‹œ์ž‘๋˜๋ฉด ํ† ํฐ์€ ๋ˆˆ๋ฉ์ด๊ฐ€ ๋œ๋‹ค. ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋กœ ์‹œ์ž‘ํ•œ ์—์ด์ „ํŠธ๋Š” ๊ทธ ์ˆœํ™˜์— ์ง„์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค.

Parism์˜ ๊ฒฝ์ œ์„ฑ์€ ์ฒญ๊ตฌ์„œ ์œ„์— ์žˆ์ง€ ์•Š๋‹ค. ํ•œ ๋ฒˆ ๋” ์ฝ๋Š” ๋น„์šฉ๋ณด๋‹ค, ํ•œ ๋ฒˆ ์ž˜๋ชป ์ฝ์–ด์„œ ์น˜๋ฅด๋Š” ๋น„์šฉ์ด ์••๋„์ ์œผ๋กœ ํฌ๋‹ค.


Parism์ด ํ•˜๋Š” ์ผ

ํ”„๋ฆฌ์ฆ˜์€ ๋น›์„ ํŒŒ๊ดดํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋ถ„ํ•ดํ•  ๋ฟ์ด๋‹ค.

"drwxr-xr-x  2 user group 4096 Mar 06 09:23 src"

                    โ†“  Parism

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

์ •๋ณด๋Š” ๋‹ฌ๋ผ์ง€์ง€ ์•Š๋Š”๋‹ค. ํ˜•ํƒœ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์—์ด์ „ํŠธ๋Š” ์ด์ œ ํŒŒ์‹ฑํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ฝ๊ธฐ๋งŒ ํ•œ๋‹ค.


์–ด๋–ป๊ฒŒ ์ข‹์€๊ฐ€

ํŒŒ์‹ฑ ์˜ค๋ฅ˜๊ฐ€ ์—†์–ด์ง„๋‹ค

ํ…์ŠคํŠธ ํŒŒ์‹ฑ์€ ๊นจ์ง€๊ธฐ ์‰ฝ๋‹ค. ps aux๋Š” ๋ฆฌ๋ˆ…์Šค์™€ macOS์—์„œ ์ปฌ๋Ÿผ ์ˆœ์„œ๊ฐ€ ๋‹ค๋ฅด๋‹ค. df -h์˜ 1K-blocks ํ—ค๋”๋Š” ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜จ๋‹ค. ํŒŒ์ผ๋ช…์— ๊ณต๋ฐฑ์ด ์žˆ์œผ๋ฉด ls ํŒŒ์‹ฑ์€ ๊ฑฐ์˜ ๋ฐ˜๋“œ์‹œ ํ‹€๋ฆฐ๋‹ค.

์ˆ˜์น˜๋กœ ๋งํ•˜๋ฉด: raw ํ…์ŠคํŠธ๋ฅผ ์—์ด์ „ํŠธ๊ฐ€ ์ง์ ‘ ํŒŒ์‹ฑํ•  ๋•Œ ํ‰๊ท  CFR(Critical Failure Rate)์€ 4.18%๋‹ค. ๊ณต๋ฐฑ์ด ํฌํ•จ๋œ ํŒŒ์ผ๋ช…์ด ์„ž์ด๋ฉด 28.6%๊นŒ์ง€ ์น˜์†Ÿ๋Š”๋‹ค. 1000ํšŒ ํ˜ธ์ถœ ์‹œ 286ํšŒ๋Š” ์ž˜๋ชป๋œ ํŒŒ์ผ ๋ชฉ๋ก์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์—์ด์ „ํŠธ๊ฐ€ ๋‹ค์Œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋Š” ๋œป์ด๋‹ค. ์ž˜๋ชป๋œ ํŒŒ์ผ์„ ์ฝ๊ณ , ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ๋กœ์— ์“ฐ๊ณ , ์—‰๋šฑํ•œ ํŒŒ์ผ์„ ์‚ญ์ œํ•œ๋‹ค.

macOS์˜ stat์€ ๋” ๊ทน์ ์ด๋‹ค. Linux์™€ ์ถœ๋ ฅ ํ˜•์‹์ด ์™„์ „ํžˆ ๋‹ค๋ฅด๋‹ค. Linux๋Š” Size: 4096์ฒ˜๋Ÿผ ๋ ˆ์ด๋ธ”์ด ๋ถ™์ง€๋งŒ, macOS๋Š” ๋ ˆ์ด๋ธ” ์—†๋Š” ๋‹จ์ผ ์ค„์ด๋‹ค. Linux ํŒŒ์‹ฑ ํŒจํ„ด์„ ์ ์šฉํ•˜๋ฉด ์ •ํ™•๋„๋Š” 0%๋‹ค. Parism์€ OS๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ์ ํ•ฉํ•œ ํŒŒ์„œ๋ฅผ ์„ ํƒํ•œ๋‹ค. ์—์ด์ „ํŠธ๋Š” ๊ทธ ์ฐจ์ด๋ฅผ ์•Œ ํ•„์š”๊ฐ€ ์—†๋‹ค.

Parism์˜ CFR์€ 0%๋‹ค. ํŒŒ์„œ๋Š” deterministic code์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ •๊ทœํ‘œํ˜„์‹ ์ถ”๋ก ์ด ์•„๋‹ˆ๋ผ ๊ตฌ์กฐ์  ๋ถ„ํ•ด๋‹ค. ์—์ด์ „ํŠธ๋Š” ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›๋Š”๋‹ค.

์žฌ์‹œ๋„๊ฐ€ ์ค„์–ด๋“ ๋‹ค

์—์ด์ „ํŠธ๊ฐ€ ์ถœ๋ ฅ์„ ์ž˜๋ชป ํ•ด์„ํ•˜๋ฉด ์žฌ์งˆ๋ฌธํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๋ช…๋ น์œผ๋กœ ๋‹ค์‹œ ํ™•์ธํ•˜๊ฑฐ๋‚˜, ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ์ง„ํ–‰ํ•œ๋‹ค. ์„ธ ๊ฐ€์ง€ ๋ชจ๋‘ ํ† ํฐ์ด ๋“ ๋‹ค. ๊ตฌ์กฐํ™”๋œ ์ถœ๋ ฅ์€ ์˜คํ•ด์˜ ์—ฌ์ง€๋ฅผ ์ค„์ธ๋‹ค. ํŒŒ์ผ์ด ๋ช‡ ๊ฐœ์ธ์ง€ ๋ฌป์ง€ ์•Š์•„๋„ entries.length๋‹ค.

์—์ด์ „ํŠธ๊ฐ€ ๋‹ค๋ฅธ ์ผ์„ ๋” ์ž˜ํ•˜๊ฒŒ ๋œ๋‹ค

ํ…์ŠคํŠธ๋ฅผ ํŒŒ์‹ฑํ•˜๋Š” ๊ฒƒ์€ ์ถ”๋ก ์ด๋‹ค. ์ถ”๋ก ์—๋Š” ์ธ์ง€ ์ž์›์ด ์†Œ๋ชจ๋œ๋‹ค. ์—์ด์ „ํŠธ๊ฐ€ ์ถœ๋ ฅ ํ˜•์‹์„ ํ•ด๋…ํ•˜๋Š” ๋ฐ ์ž์›์„ ์“ฐ๋ฉด, ์‹ค์ œ ์ž‘์—… โ€” ์ฝ”๋“œ๋ฅผ ๋ถ„์„ํ•˜๊ณ , ์„ค๊ณ„๋ฅผ ํŒ๋‹จํ•˜๊ณ , ๋‹ค์Œ ๋‹จ๊ณ„๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ์ผ โ€” ์— ์“ธ ์ž์›์ด ์ค„์–ด๋“ ๋‹ค. ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์œผ๋ฉด ํŒŒ์‹ฑ์ด๋ผ๋Š” ์ž‘์—… ์ž์ฒด๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค. ์—์ด์ „ํŠธ๋Š” ์ฝ๊ธฐ๋งŒ ํ•˜๋ฉด ๋˜๊ณ , ๋‚จ์€ ์—ญ๋Ÿ‰์„ ๋ณธ๋ž˜์˜ ์ž‘์—…์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

raw๊ฐ€ ํ•ญ์ƒ ๋ณด์กด๋œ๋‹ค

ํŒŒ์„œ๊ฐ€ ํ‹€๋ฆด ์ˆ˜๋„ ์žˆ๋‹ค. ํŒŒ์„œ๊ฐ€ ์—†๋Š” ๋ช…๋ น์–ด์ผ ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ Parism์€ raw๋ฅผ ํ•ญ์ƒ ์œ ์ง€ํ•œ๋‹ค. parsed๋Š” ๋ณด๋„ˆ์Šค๋‹ค. raw๋Š” ๋ณดํ—˜์ด๋‹ค. ์—์ด์ „ํŠธ๋Š” ํ•ญ์ƒ ์›๋ณธ์œผ๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋‹ค.

"stdout": {
  "raw": "drwxr-xr-x ...",
  "parsed": { "entries": [ ... ] }
}

์‘๋‹ต ๊ตฌ์กฐ๊ฐ€ ์ผ์ •ํ•˜๋‹ค

์„ฑ๊ณต์ด๋“  ์‹คํŒจ๋“ , ok์™€ exitCode๋Š” ํ•ญ์ƒ ๊ฐ™์€ ์ž๋ฆฌ์— ์žˆ๋‹ค. ์—์ด์ „ํŠธ๊ฐ€ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด ๋‹จ์ˆœํ•ด์ง„๋‹ค. "stdout์„ ํŒŒ์‹ฑํ•ด์„œ ์˜ค๋ฅ˜์ธ์ง€ ํ™•์ธ"์ด ์•„๋‹ˆ๋ผ if (!result.ok)๋‹ค.

์‹คํ–‰ ์‹œ๊ฐ„์ด ๊ธฐ๋ก๋œ๋‹ค

๋ชจ๋“  ์‘๋‹ต์— duration_ms๊ฐ€ ํฌํ•จ๋œ๋‹ค. ๋ช…๋ น์ด ๋А๋ฆฐ์ง€ ๋น ๋ฅธ์ง€๋ฅผ ์—์ด์ „ํŠธ๊ฐ€ ํŒ๋‹จํ•˜๋Š” ๋ฐ ์“ธ ์ˆ˜ ์žˆ๋‹ค. ๋””๋ฒ„๊น…ํ•  ๋•Œ๋„ ์œ ์šฉํ•˜๋‹ค.

diff๋Š” ์„ ํƒ์ ์ด๋‹ค

includeDiff: true์ผ ๋•Œ๋งŒ diff์— created, deleted, modified๊ฐ€ ์ฑ„์›Œ์ง„๋‹ค. run/run_paged ๊ธฐ๋ณธ๊ฐ’์€ includeDiff: false์ด๋ฏ€๋กœ ์Šค๋ƒ…์ƒท ๋น„์šฉ์„ ์ƒ๋žตํ•˜์—ฌ MCP ํ˜ธ์ถœ ์ง€์—ฐ์„ ์ค„์ธ๋‹ค.


๊ฐ€๋“œ โ€” ์—์ด์ „ํŠธ๋ฅผ ์‹ ๋ขฐํ•˜์ง€ ์•Š๋Š” ์ด์œ 

rm -rf /๋Š” ์„ธ ๊ฐœ์˜ ๋ฌธ์ž๋กœ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

์—์ด์ „ํŠธ๋Š” ์˜ค๋ฅ˜๋ฅผ ๋ฒ”ํ•œ๋‹ค. ๋ฌธ๋งฅ์„ ์žƒ๊ณ , ๊ฒฝ๋กœ๋ฅผ ์ฐฉ๊ฐํ•˜๊ณ , ์˜๋„ํ•˜์ง€ ์•Š์€ ๋ช…๋ น์„ ์ƒ์„ฑํ•œ๋‹ค. Guard๋Š” ์—์ด์ „ํŠธ๋ฅผ ๋ถˆ์‹ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ์—์ด์ „ํŠธ์˜ ์‹ค์ˆ˜๊ฐ€ ํŒŒ๊ตญ์œผ๋กœ ์ด์–ด์ง€์ง€ ์•Š๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋„ค ๊ฒน์˜ ๋ฐฉ์–ด์„ ์ด ์žˆ๋‹ค.

ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ: allowed_commands์— ์—†๋Š” ๋ช…๋ น์–ด๋Š” ์‹คํ–‰๋˜์ง€ ์•Š๋Š”๋‹ค. ํ”„๋กœ์„ธ์Šค๋ฅผ ๋งŒ๋“ค์ง€๋„ ์•Š๋Š”๋‹ค. ์„ค๋ช… ์—†์ด ๊ฑฐ์ ˆํ•œ๋‹ค.

๊ฒฝ๋กœ ์ œํ•œ: allowed_paths๋ฅผ ์„ค์ •ํ•˜๋ฉด cwd์™€ ๊ฒฝ๋กœ ์ธ์ž๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. /, ./, ../๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ธ์ž์™€, cat, find, ls, grep, git, docker, kubectl, cargo ๋“ฑ ๊ฒฝ๋กœ๋ฅผ ๋ฐ›๋Š” ๋ช…๋ น์˜ positional ์ธ์ž(cat subdir/file, find src)๋„ ํ—ˆ์šฉ ๊ฒฝ๋กœ ๋ฐ–์ด๋ฉด ์ฐจ๋‹จ๋œ๋‹ค. ์ปค๋„ ์ˆ˜์ค€ ์ƒŒ๋“œ๋ฐ•์Šค๋Š” ์•„๋‹ˆ๋ฉฐ, ๊ฐ€๋“œ ์ˆ˜์ค€์˜ ๋ฐฉ์–ด์„ ์ด๋‹ค.

์ธ์ ์…˜ ํŒจํ„ด ์ฐจ๋‹จ: ๊ฐ ์ธ์ž๋ฅผ ๊ฐœ๋ณ„์ ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉฐ ;, $(, `, &&, ||, |, >, >>, <๊ฐ€ ํฌํ•จ๋˜๋ฉด ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ธ์ž ๋‹จ์œ„ ๊ฒ€์‚ฌ์ด๋ฏ€๋กœ ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์ž ๊ฒฝ๊ณ„๋ฅผ ๋„˜์–ด์„œ๋Š” ์˜คํƒ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ช…๋ น๋ณ„ ์ธ์ž ์ œํ•œ: ๋ช…๋ น๋งˆ๋‹ค ์ฐจ๋‹จํ•  ํ”Œ๋ž˜๊ทธ๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. node -e, node --eval, node --input-type์€ ๊ธฐ๋ณธ ์ฐจ๋‹จ๋œ๋‹ค. npx --yes๋„ ๊ธฐ๋ณธ ์ฐจ๋‹จ๋œ๋‹ค.

์ฐจ๋‹จ๋œ ๋ช…๋ น์€ ์ด๋Ÿฐ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

{
  "ok": false,
  "guard_error": {
    "reason": "command_not_allowed",
    "message": "Command 'rm' is not in the allowed list"
  },
  "failure": {
    "kind": "guard",
    "reason": "command_not_allowed",
    "message": "Command 'rm' is not in the allowed list"
  }
}

v0.6 ๋ถ€ํ„ฐ failure ํ•„๋“œ๊ฐ€ ๊ถŒ์œ„ ํ•„๋“œ๋‹ค. guard_error ๋Š” ํ•˜์œ„ ํ˜ธํ™˜์„ ์œ„ํ•ด ์œ ์ง€๋œ๋‹ค. ์—์ด์ „ํŠธ๋Š” result.failure.kind ๋กœ ๋ถ„๊ธฐํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

์—์ด์ „ํŠธ๋Š” ์‹คํ–‰ ๊ฒฐ๊ณผ์™€ ๋™์ผํ•œ ๊ตฌ์กฐ๋กœ ์ฐจ๋‹จ ์ด์œ ๋ฅผ ๋ฐ›๋Š”๋‹ค. ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์ง€์ง€ ์•Š๋Š”๋‹ค. ํŒŒ์ดํ”„๋ผ์ธ์ด ๊นจ์ง€์ง€ ์•Š๋Š”๋‹ค.

Guard์˜ ์œ„ํ˜‘ ๋ชจ๋ธ, 4๊ฒน ๋ฐฉ์–ด์„ ์˜ ํ•œ๊ณ„, ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ํ™˜๊ฒฝ์—์„œ์˜ ๊ฒฉ๋ฆฌ ๊ถŒ๊ณ ๋Š” SECURITY.md๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.


์ง€์› ๋ช…๋ น์–ด โ€” 44์ข… ๋‚ด์žฅ ํŒŒ์„œ

์นดํ…Œ๊ณ ๋ฆฌ๋ช…๋ น์–ดํŒŒ์‹ฑ ๊ฒฐ๊ณผ๊ธฐ๋ณธ ํ—ˆ์šฉ
ํŒŒ์ผ์‹œ์Šคํ…œlsentries[] โ€” ์ด๋ฆ„, ํƒ€์ž…, ๊ถŒํ•œ, ํฌ๊ธฐ, ์ˆ˜์ • ์‹œ๊ฐ, ์†Œ์œ ์žO
ํŒŒ์ผ์‹œ์Šคํ…œfindpaths[] โ€” ๊ฒฝ๋กœ ๋ชฉ๋กO
ํŒŒ์ผ์‹œ์Šคํ…œstatfile, size_bytes, inode, permissions, uid, gid, ํƒ€์ž„์Šคํƒฌํ”„O
ํŒŒ์ผ์‹œ์Šคํ…œduentries[] โ€” ํฌ๊ธฐ, ๊ฒฝ๋กœO
ํŒŒ์ผ์‹œ์Šคํ…œdffilesystems[] โ€” ํŒŒํ‹ฐ์…˜, ์‚ฌ์šฉ๋Ÿ‰, ๋งˆ์šดํŠธ ์œ„์น˜O
ํŒŒ์ผ์‹œ์Šคํ…œtreeroot, tree{} โ€” ๊ณ„์ธต ๊ตฌ์กฐ ๋…ธ๋“œ, total_files, total_dirsO
ํ”„๋กœ์„ธ์Šคpsprocesses[] โ€” PID, CPU%, MEM%, ๋ช…๋ น์–ดO
ํ”„๋กœ์„ธ์Šคkillraw pass-through (๊ธฐ๋ณธ ์ฐจ๋‹จ, prism.config.json์—์„œ ๋ช…์‹œ์  ํ—ˆ์šฉ ์‹œ ์‚ฌ์šฉ)X
๋„คํŠธ์›Œํฌpingtarget, packets_transmitted, packet_loss_percent, rtt_*_msO
๋„คํŠธ์›Œํฌcurl -Istatus_code, headers{}O
๋„คํŠธ์›Œํฌnetstatconnections[] โ€” proto, local/foreign address, stateO
๋„คํŠธ์›Œํฌlsof -ientries[] โ€” PID, ํ”„๋กœ์„ธ์Šค๋ช…, ํ”„๋กœํ† ์ฝœ, ๋กœ์ปฌ/์›๊ฒฉ ์ฃผ์†Œ, ์ƒํƒœX
๋„คํŠธ์›Œํฌssentries[] โ€” ์ƒํƒœ, ์ˆ˜์‹ /๋ฐœ์‹  ํ, ๋กœ์ปฌ/ํ”ผ์–ด ์ฃผ์†Œ, ํ”„๋กœ์„ธ์ŠคX
๋„คํŠธ์›Œํฌdigquery, answers[] โ€” ํƒ€์ž…, ๊ฐ’, TTL, query_time_msX
ํ…์ŠคํŠธgrep -nmatches[] โ€” ํŒŒ์ผ, ๋ผ์ธ ๋ฒˆํ˜ธ, ํ…์ŠคํŠธO
ํ…์ŠคํŠธwcentries[] โ€” count, ํŒŒ์ผ๋ช…O
ํ…์ŠคํŠธhead, tail, catlines[]O
Gitgit statusbranch, staged[], modified[], untracked[]O
Gitgit log --onelinecommits[] โ€” hash, messageO
Gitgit difffiles_changed[]O
Gitgit branch -vvbranches[] โ€” ์ด๋ฆ„, current, upstream, ahead/behindO
DevOpskubectl get pods, kubectl get eventspods[]/events[] โ€” ์ƒํƒœ, ์žฌ์‹œ๋„, ์ด๋ฒคํŠธ ์‚ฌ์œ /๋ฉ”์‹œ์ง€O
DevOpsdocker ps, docker stats --no-streamcontainers[]/stats[] โ€” ์ด๋ฏธ์ง€, ์ƒํƒœ, CPU/MEM/IOO
DevOpsgh pr listpull_requests[] โ€” ๋ฒˆํ˜ธ, ์ œ๋ชฉ, ์ƒํƒœ, ์ž‘์„ฑ์ž, ๋ผ๋ฒจO
DevOpshelm listreleases[] โ€” name, namespace, status, chart, app_versionO
DevOpsterraform plansummary โ€” to_add, to_change, to_destroyO
ํ™˜๊ฒฝenvvars{} โ€” ํ‚ค-๊ฐ’ ๋งตO
ํ™˜๊ฒฝpwdpathO
ํ™˜๊ฒฝwhichpaths[]O
์‹œ์Šคํ…œfreerows{} โ€” mem/swap๋ณ„ total, used, free, available (bytes)X
์‹œ์Šคํ…œunamekernel, hostname, release, version, arch, osO
์‹œ์Šคํ…œiduid, gid, username, groups[] โ€” id, nameX
์‹œ์Šคํ…œsystemctl list-unitsunits[] โ€” name, load, active, sub, description (Linux)O
์‹œ์Šคํ…œjournalctl -o short-isoentries[] โ€” timestamp, hostname, unit, pid, message (Linux)O
์‹œ์Šคํ…œapt list --installedpackages[] โ€” name, version, arch, statusO
์‹œ์Šคํ…œbrew list --versionspackages[] โ€” name, versionO
ํŒจํ‚ค์ง€npm list, pnpm list, yarn listdependencies[] โ€” name, version, depthO
ํŒจํ‚ค์ง€cargo treecrates[] โ€” name, version, pathO
Windowsdirdirectory, entries[] โ€” ์ด๋ฆ„, ํƒ€์ž…, ํฌ๊ธฐ, ์ˆ˜์ • ์‹œ๊ฐ, free_bytesX
Windowstasklistprocesses[] โ€” ์ด๋ฆ„, PID, ์„ธ์…˜, ๋ฉ”๋ชจ๋ฆฌ. CSV ํ˜•์‹ ์ง€์›X
Windowsipconfighostname, adapters[] โ€” IPv4/6, ์„œ๋ธŒ๋„ท, ๊ฒŒ์ดํŠธ์›จ์ด, DNS, MACX
Windowssysteminfohostname, os_name, ๋ฉ”๋ชจ๋ฆฌ, hotfixes[], network_cards[]X

๊ธฐ๋ณธ ํ—ˆ์šฉ(O)=DEFAULT_CONFIG์— ํฌํ•จ. X=prism.config.json์—์„œ ๋ช…์‹œ์  ํ—ˆ์šฉ ํ•„์š”.

ํŒŒ์„œ๊ฐ€ ์—†๋Š” ๋ช…๋ น์–ด๋Š” parsed: null๋กœ ๋ฐ˜ํ™˜๋œ๋‹ค. raw๋Š” ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค. ํŒŒ์„œ๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋ฉด stdout.parse_error์— { reason: "parser_exception", message: string }๊ฐ€ ํฌํ•จ๋˜์–ด "ํŒŒ์„œ ์—†์Œ"๊ณผ "ํŒŒ์„œ ๋ฒ„๊ทธ"๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

v0.6 ๋ถ€ํ„ฐ parse_error.reason ์€ "parser_exception", "parser_not_found", "schema_violation" ์„ธ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ๊ฐ™์€ ์ •๋ณด๊ฐ€ result.failure.kind === "parse" ๋กœ๋„ ๋…ธ์ถœ๋œ๋‹ค.

๋„ค์ดํ‹ฐ๋ธŒ JSON ํŒจ์Šค์Šค๋ฃจ

ํŒŒ์„œ๊ฐ€ ์—†๋Š” ๋ช…๋ น์ด๋ผ๋„ ์ถœ๋ ฅ ์ž์ฒด๊ฐ€ JSON์ด๋ฉด(์˜ˆ: kubectl get pods -o json, docker inspect) Parism์ด ์ด๋ฅผ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜์—ฌ parsed์— ๋„ฃ๋Š”๋‹ค. Guard ๊ฒ€์‚ฌ์™€ ๋ด‰ํˆฌ ๋ž˜ํ•‘์€ ๋™์ผํ•˜๊ฒŒ ์ ์šฉ๋œ๋‹ค. ๋ณ„๋„ ์„ค์ •์€ ํ•„์š” ์—†๋‹ค.


์„ค์น˜

npx

npx @nerdvana/parism

๋กœ์ปฌ ๋นŒ๋“œ

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

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ๋“œ

MCP ์„œ๋ฒ„ ์—†์ด Node.js ํ”„๋กœ์„ธ์Šค ๋‚ด๋ถ€์—์„œ Parism ์„ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. v1.0.0 ๋ถ€ํ„ฐ ์ •์‹ API ๋‹ค. Semantic Versioning ์„ ๋”ฐ๋ฅด๋ฉฐ, breaking change ๋Š” v2.0.0 ์—์„œ๋งŒ ๋ฐœ์ƒํ•œ๋‹ค.

์ตœ์†Œ ์˜ˆ์‹œ:

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

const engine = await createEngine();
const result = await engine.run("ls", { args: ["-la"] });
console.log(result.stdout.parsed);

createEngine()์€ prism.config.json์„ ๋กœ๋“œํ•˜๊ณ  ์™ธ๋ถ€ ํŒŒ์„œ๋ฅผ ๋“ฑ๋กํ•œ ๋’ค ParismEngine ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ปค์Šคํ…€ ์„ค์ • ๊ฒฝ๋กœ๊ฐ€ ํ•„์š”ํ•˜๋ฉด createEngine({ configPath: "/path/to/prism.config.json" })์„ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค์ • ๊ฒฝ๋กœ ์ง€์ •๊ณผ failure ๋ถ„๊ธฐ๋ฅผ ํ•จ๊ป˜ ์“ฐ๋Š” ์‹ค์šฉ ์˜ˆ์‹œ:

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

const engine = await createEngine({
  configPath: "/path/to/custom/prism.config.json",
});

const result = await engine.run("git", { args: ["status", "--porcelain"] });

if (!result.ok) {
  console.error(`[${result.failure?.kind}] ${result.failure?.reason}: ${result.failure?.message}`);
  process.exit(1);
}

console.log(result.stdout.parsed);

RunOptions โ€” args / cwd / format / includeDiff. RunPagedOptions โ€” ์œ„ ์˜ต์…˜ ์ „์ฒด + page / page_size.

์„ค๊ณ„ ์ƒ์„ธ๋Š” SPECIFICATION.md ยง1.1 ์ฐธ์กฐ.


MCP ํด๋ผ์ด์–ธํŠธ ์„ค์ •

Parism ์€ MCP stdio ํ”„๋กœํ† ์ฝœ์„ ํ†ตํ•ด ์ฃผ์š” AI CLI/IDE ์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋ณ„ ์ƒ์„ธ ์„ค์ •์€ docs/mcp-clients/ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ๊ฐ€์ด๋“œ
Claude Desktopdocs/mcp-clients/claude-desktop.md
Claude Codedocs/mcp-clients/claude-code.md
Cursordocs/mcp-clients/cursor.md
Gemini CLIdocs/mcp-clients/gemini-cli.md
Codex CLIdocs/mcp-clients/codex.md
GitHub Copilot CLIdocs/mcp-clients/copilot-cli.md

์—ฐ๊ฒฐ์ด ์„ฑ๊ณตํ•˜๋ฉด run, run_paged, describe, dry_run ๋„ค ๋„๊ตฌ๊ฐ€ ๋…ธ์ถœ๋œ๋‹ค. ์—์ด์ „ํŠธ๋Š” ๋จผ์ € describe๋กœ ํ—ˆ์šฉ ๋ช…๋ น๊ณผ ํŒŒ์„œ๋ฅผ ํŒŒ์•…ํ•˜๊ณ , dry_run์œผ๋กœ guard ํ†ต๊ณผ ์—ฌ๋ถ€๋ฅผ ์‚ฌ์ „ ํ™•์ธํ•œ ๋’ค, run / run_paged๋กœ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ JSON ์‘๋‹ต์„ ๋ฐ›๋Š”๋‹ค.


Tools

run

๋ชจ๋“  ๋ช…๋ น์˜ ๊ธฐ๋ณธ ๋„๊ตฌ. ์ถœ๋ ฅ์ด ์ž‘๊ฑฐ๋‚˜ ๊ตฌ์กฐํ™” ํŒŒ์‹ฑ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • cmd โ€” ๋ช…๋ น์–ด ์ด๋ฆ„ (์˜ˆ: ls, git)
  • args โ€” ์ธ์ž ๋ฐฐ์—ด (๊ธฐ๋ณธ๊ฐ’: [])
  • cwd โ€” ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ (๊ธฐ๋ณธ๊ฐ’: ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ)
  • format โ€” ์ถœ๋ ฅ ํ˜•์‹ ("json" ๊ธฐ๋ณธ๊ฐ’, "compact", "json-no-raw"). compact๋Š” ๋ฆฌ์ŠคํŠธํ˜• ์ถœ๋ ฅ์„ schema+rows ์ปฌ๋Ÿผ ๊ธฐ๋ฐ˜์œผ๋กœ ์••์ถ•ํ•˜์—ฌ ํ† ํฐ ๋น„์šฉ์„ ์ ˆ๊ฐํ•œ๋‹ค.
  • includeDiff โ€” ํŒŒ์ผ์‹œ์Šคํ…œ diff ํฌํ•จ ์—ฌ๋ถ€ (๊ธฐ๋ณธ๊ฐ’: false). false๋ฉด ์Šค๋ƒ…์ƒท ์ƒ๋žต์œผ๋กœ ์ง€์—ฐ ๊ฐ์†Œ. MCP ๊ณ ๋นˆ๋„ ํ˜ธ์ถœ ์‹œ ๊ถŒ์žฅ.

compact ์˜ˆ์‹œ:

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

run_paged

๋Œ€์šฉ๋Ÿ‰ ์ถœ๋ ฅ์„ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ฝ๋Š”๋‹ค. ps aux, find, grep -r ๋“ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • cmd, args, cwd โ€” run๊ณผ ๋™์ผ
  • page โ€” 0-indexed ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ (๊ธฐ๋ณธ๊ฐ’: 0)
  • page_size โ€” ํŽ˜์ด์ง€๋‹น ์ค„ ์ˆ˜ (๊ธฐ๋ณธ๊ฐ’: default_page_size ์„ค์ •๊ฐ’, ๊ธฐ๋ณธ 100)
  • includeDiff โ€” ํŒŒ์ผ์‹œ์Šคํ…œ diff ํฌํ•จ ์—ฌ๋ถ€ (๊ธฐ๋ณธ๊ฐ’: false). false๋ฉด ์Šค๋ƒ…์ƒท ์ƒ๋žต์œผ๋กœ ์ง€์—ฐ ๊ฐ์†Œ.

์‘๋‹ต ์ถ”๊ฐ€ ํ•„๋“œ:

  • page_info.total_lines โ€” ์ „์ฒด ์ค„ ์ˆ˜
  • page_info.has_next โ€” ๋‹ค์Œ ํŽ˜์ด์ง€ ์กด์žฌ ์—ฌ๋ถ€
  • stdout.parsed โ€” ํ•ญ์ƒ null (๋ถ€๋ถ„ ์ถœ๋ ฅ์€ ๊ตฌ์กฐํ™” ๋ถˆ๊ฐ€)

์—์ด์ „ํŠธ ํŒจํ„ด:

1. run_paged(cmd, page=0) โ†’ page_info.total_lines ํ™•์ธ
2. ๋ฒ”์œ„๊ฐ€ ์ž‘์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
3. ๋ฒ”์œ„๊ฐ€ ํฌ๋ฉด grep์œผ๋กœ ๋จผ์ € ํ•„ํ„ฐ๋ง ํ›„ run ํ˜ธ์ถœ
4. ํ•„์š”ํ•œ ํŽ˜์ด์ง€๋งŒ run_paged(page=N) ์ถ”๊ฐ€ ํ˜ธ์ถœ

describe

์—์ด์ „ํŠธ ์˜จ๋ณด๋”ฉ ๋„๊ตฌ. ํ˜„์žฌ ํ™˜๊ฒฝ์˜ ํ—ˆ์šฉ ๋ช…๋ น, ์‚ฌ์šฉ ๊ฐ€๋Šฅ ํŒŒ์„œ, guard ์ œํ•œ, ๋ฒ„์ „ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ: ์—†์Œ.

์‘๋‹ต:

  • version โ€” Parism ํŒจํ‚ค์ง€ ๋ฒ„์ „
  • allowed_commands โ€” guard์—์„œ ํ—ˆ์šฉํ•˜๋Š” ๋ช…๋ น ๋ชฉ๋ก
  • available_parsers โ€” ๋“ฑ๋ก๋œ ํŒŒ์„œ ์ด๋ฆ„ ๋ชฉ๋ก
  • guard_summary โ€” timeout_ms, max_output_bytes, max_items, block_patterns_count, allowed_paths
  • telemetry_enabled โ€” ํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ํ™œ์„ฑํ™” ์—ฌ๋ถ€

์—์ด์ „ํŠธ๊ฐ€ Parism์„ ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ ์ด ๋„๊ตฌ๋ฅผ ๋จผ์ € ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ€์šฉ ๋ช…๋ น๊ณผ ์ œํ•œ ์‚ฌํ•ญ์„ ํ•œ๋ˆˆ์— ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.

dry_run

guard ์‚ฌ์ „ ๊ฒ€์ฆ ๋„๊ตฌ. ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  guard ํ†ต๊ณผ ์—ฌ๋ถ€๋งŒ ํ™•์ธํ•œ๋‹ค.

ํŒŒ๋ผ๋ฏธํ„ฐ:

  • cmd โ€” ๋ช…๋ น์–ด ์ด๋ฆ„ (์˜ˆ: rm, git)
  • args โ€” ์ธ์ž ๋ฐฐ์—ด (๊ธฐ๋ณธ๊ฐ’: [])
  • cwd โ€” ์ž‘์—… ๋””๋ ‰ํ† ๋ฆฌ (๊ธฐ๋ณธ๊ฐ’: ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ)

์‘๋‹ต:

  • would_pass โ€” guard ํ†ต๊ณผ ์—ฌ๋ถ€
  • reason โ€” ์ฐจ๋‹จ ์‹œ ์‚ฌ์œ  (command_not_allowed, path_not_allowed, injection_pattern, arg_not_allowed)
  • message โ€” ์ฐจ๋‹จ ์‹œ ์ƒ์„ธ ๋ฉ”์‹œ์ง€

์˜ˆ: dry_run("rm", ["-rf", "/"]) โ†’ { would_pass: false, reason: "command_not_allowed", message: "..." }


์„ค์ •

prism.config.json์„ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— ๋‘๋ฉด Guard ๋™์ž‘์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

{
  "guard": {
    "allowed_commands": ["ls", "git", "find", "grep", "env", "ps"],
    "allowed_paths": ["/home/user/projects"],
    "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_patterns": ["Bearer [A-Za-z0-9._\\-]+", "ghp_[A-Za-z0-9]+"],
      "output_redaction_enabled": false
    }
  },
  "parsers": {
    "strict_schemas": false
  },
  "telemetry": {
    "enabled": false
  }
}

allowed_paths๊ฐ€ ๋น„์–ด ์žˆ์œผ๋ฉด ๊ฒฝ๋กœ ์ œํ•œ ์—†์ด ์‹คํ–‰๋œ๋‹ค. ํŒ๋‹จ์€ ๋‹น์‹  ๋ชซ์ด๋‹ค.

guard.secrets.env_patterns์— ์ผ์น˜ํ•˜๋Š” ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋Š” ์‹คํ–‰ ์ „ ์ž์‹ ํ”„๋กœ์„ธ์Šค์—์„œ ์ œ๊ฑฐ๋œ๋‹ค. env ๋ช…๋ น ์‹คํ–‰ ์‹œ ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š๋Š”๋‹ค.

guard.secrets.output_redaction_enabled๋Š” ๊ธฐ๋ณธ false ๋กœ opt-in ๋ฐฉ์‹์ด๋‹ค. true ๋กœ ์„ค์ •ํ•˜๋ฉด output_patterns ์— ๋งค์นญ๋˜๋Š” ๋ฌธ์ž์—ด์„ ๋ช…๋ น ์‹คํ–‰ ํ›„ raw ์ถœ๋ ฅ์—์„œ [REDACTED] ๋กœ ๋Œ€์ฒดํ•œ๋‹ค. ํŒŒ์‹ฑ ์ „์— ์ ์šฉ๋˜๋ฏ€๋กœ stdout.parsed ๊ฒฐ๊ณผ์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

command_arg_restrictions๋Š” ๊ธฐ๋ณธ๊ฐ’๊ณผ ๋ณ‘ํ•ฉ๋œ๋‹ค. ์ผ๋ถ€ ๋ช…๋ น๋งŒ overrideํ•ด๋„ ๋‚˜๋จธ์ง€ ๊ธฐ๋ณธ ์ œํ•œ์€ ์œ ์ง€๋œ๋‹ค.

parsers.strict_schemas๋ฅผ true ๋กœ ์„ค์ •ํ•˜๋ฉด ๊ฐ ํŒŒ์„œ์˜ Zod ์Šคํ‚ค๋งˆ๋กœ ํŒŒ์‹ฑ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ฆํ•œ๋‹ค. ์Šคํ‚ค๋งˆ ์œ„๋ฐ˜ ์‹œ failure.reason === "schema_violation" ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ๊ธฐ๋ณธ false ์ด๋ฉฐ opt-in ๋ฐฉ์‹์ด๋‹ค.

telemetry.enabled๋ฅผ true๋กœ ์„ค์ •ํ•˜๋ฉด ์‘๋‹ต ๋ด‰ํˆฌ์— telemetry ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค. guard/exec/parse/redact ๊ฐ ๋‹จ๊ณ„์˜ ์†Œ์š” ์‹œ๊ฐ„(ms)๊ณผ raw ์ถœ๋ ฅ ๋ฐ”์ดํŠธ ์ˆ˜๋ฅผ ํฌํ•จํ•œ๋‹ค. ๊ธฐ๋ณธ false์ด๋ฉฐ opt-in ๋ฐฉ์‹์ด๋‹ค.

legacy env_secret_patterns ๋Š” v2.0.0 ์—์„œ ์ œ๊ฑฐ๋œ๋‹ค. ์‚ฌ์šฉ ์‹œ stderr ์— deprecation ๊ฒฝ๊ณ ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค.


์ปค์Šคํ…€ ํŒŒ์„œ -- ์ง์ ‘ ๋งŒ๋“ค๊ณ  ๋ฐ”๋กœ ์“ด๋‹ค

44๊ฐœ ๋‚ด์žฅ ํŒŒ์„œ๋กœ ๋ถ€์กฑํ•˜๋ฉด, ์ง์ ‘ ๋งŒ๋“ค๋ฉด ๋œ๋‹ค. Parism v0.5.0 ๋ถ€ํ„ฐ CLI ๋„๊ตฌ๊ฐ€ ํฌํ•จ๋œ๋‹ค. v1.0.0 ๋ถ€ํ„ฐ ParserPack.schema ๋Š” Zod ์Šคํ‚ค๋งˆ๋ฅผ ๋‹จ์ผ ์†Œ์Šค๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

5๋ถ„ ์•ˆ์— ํŒŒ์„œ ๋งŒ๋“ค๊ธฐ

# 1. ๋ช…๋ น์–ด ์ถœ๋ ฅ์„ ์บก์ฒ˜ํ•œ๋‹ค
parism capture "htop -b -n 1"

# 2. ํŒŒ์„œ ํŒฉ ์Šค์บํด๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค
parism init-parser htop

# 3. parser.ts๋ฅผ ํŽธ์ง‘ํ•˜๊ณ  fixture๋ฅผ ํ…Œ์ŠคํŠธํ•œ๋‹ค
parism test htop

# 4. ๋“ฑ๋กํ•œ๋‹ค -- ์žฌ์‹œ์ž‘ ์—†์ด ์ฆ‰์‹œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
parism add ./htop

# 5. ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•œ๋‹ค -- raw/parsed/compact ๋น„๊ต + ํ† ํฐ ์ˆ˜
parism inspect "htop -b -n 1"

๋“ฑ๋ก๋œ ํŒŒ์„œ๋Š” ~/.parism/parsers/์— ์ €์žฅ๋˜๊ณ , MCP ์„œ๋ฒ„ ์‹œ์ž‘ ์‹œ ์ž๋™์œผ๋กœ ๋กœ๋“œ๋œ๋‹ค.

CLI ๋ช…๋ น์–ด

๋ช…๋ น์–ด์„ค๋ช…
parism capture "<command>"๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๊ณ  raw ์ถœ๋ ฅ์„ fixture๋กœ ์ €์žฅ
parism init-parser <name>TypeScript ํŒŒ์„œ ํŒฉ ์Šค์บํด๋“œ ์ƒ์„ฑ (parser.ts + schema.json + fixtures/)
parism test [parser]fixture replay ํ…Œ์ŠคํŠธ ์‹คํ–‰
parism add <path>๋กœ์ปฌ ํŒŒ์„œ ํŒฉ์„ ~/.parism/parsers/์— ์˜๊ตฌ ๋“ฑ๋ก
parism inspect "<command>"raw / parsed / compact ์ถœ๋ ฅ ๋น„๊ต + ํ† ํฐ ์ˆ˜

ParserPack ์ธํ„ฐํŽ˜์ด์Šค

์™ธ๋ถ€ ํŒŒ์„œ๋Š” ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.

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

const pack: ParserPack = {
  name: "my-command",
  parse(raw, args, ctx?) { /* ๊ตฌ์กฐํ™”๋œ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ */ },
  schema: { /* JSON Schema */ },
  fixtures: [{ input: "...", args: [], expected: { /* ... */ } }],
};

export default pack;

์ธ์ž ์—†์ด parism์„ ์‹คํ–‰ํ•˜๋ฉด ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ MCP ์„œ๋ฒ„๋กœ ๋™์ž‘ํ•œ๋‹ค.


Parism์ด ์•„๋‹Œ ๊ฒƒ

Parism์€ ์ƒˆ๋กœ์šด ์…ธ์ด ์•„๋‹ˆ๋‹ค. bash๋ฅผ ๋Œ€์ฒดํ•˜์ง€ ์•Š๋Š”๋‹ค. bash ์œ„์— ์•‰์•„์„œ ์ถœ๋ ฅ์„ ๋ฐ›์•„ ๊ตฌ์กฐํ™”ํ•  ๋ฟ์ด๋‹ค.

Parism์€ AI๋ฅผ ์œ„ํ•œ ์šด์˜์ฒด์ œ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ด€์‹ฌ์‚ฌ๋Š” ํ•˜๋‚˜๋‹ค. ์—์ด์ „ํŠธ๊ฐ€ ๋ช…๋ น์„ ๋‚ด๋ ธ์„ ๋•Œ, ์—์ด์ „ํŠธ๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค์ฃผ๋Š” ๊ฒƒ.

Unix ์ฒ ํ•™์€ "ํ•˜๋‚˜์˜ ์ผ์„ ์ž˜ ํ•˜๋ผ"์˜€๋‹ค. Parism์€ ๊ทธ๊ฒƒ์„ ์ดํ•ดํ•œ๋‹ค.


Made by Jinho Choi ย |ย  Buy me a coffee