명령줄 도구
편집기를 여는 바로 그 프로그램 baram은 터미널에서 볼트에 대한 질문에도 답합니다. 스크립트와 AI 에이전트를 위한 기능입니다. 앱을 열지 않고도 노트를 검색하고, 태스크를 나열하고, 링크를 따라갈 수 있습니다.
모든 명령은 읽기만 합니다. 볼트의 파일도, 앱의 설정도 바꾸는 명령은 없습니다.
실행하기
섹션 제목: “실행하기”이 명령은 앱의 실행 파일 그 자체입니다. 따로 설치할 것이 없습니다.
| 플랫폼 | 실행 방법 |
|---|---|
| macOS | /Applications/Baram.app/Contents/MacOS/baram |
Linux (.deb) |
baram — 패키지가 PATH에 넣어 줍니다 |
| Windows | 아직 확인되지 않았습니다. 명령은 들어 있지만, 출력이 터미널에 나오는지 확인한 사람이 없습니다. |
macOS에서는 셸 함수를 만들어 두면 전체 경로를 치지 않아도 됩니다. ~/.zshrc에 넣습니다.
baram() { /Applications/Baram.app/Contents/MacOS/baram "$@"; }함수나 alias는 ~/.zshrc를 읽는 셸에만 있습니다. 스크립트에서는 전체 경로로 부르거나, baram이라는 이름의 작은 스크립트를 PATH에 두십시오.
#!/bin/shexec /Applications/Baram.app/Contents/MacOS/baram "$@"심볼릭 링크 대신 이 가운데 하나를 쓰십시오. 앱이 링크를 통해 시작되면 업데이트 뒤에 스스로 다시 시작하지 못합니다.
인자 없이 실행하거나 첫 인자가 절대 경로나 URL이면 baram은 평소처럼 앱을 엽니다. baram --help가 명령 목록을 보여 줍니다.
볼트 고르기
섹션 제목: “볼트 고르기”명령 하나는 볼트 하나를 읽습니다. --vault가 두 가지 형태 가운데 하나로 볼트를 정하고, 이 플래그가 없으면 현재 디렉터리가 정합니다.
--vault <경로>— 폴더입니다. 값에/가 있거나(Windows에서는\도).또는~로 시작하면 경로로 읽습니다. 상대 경로는 현재 디렉터리에서 시작합니다. 앱에 등록된 폴더가 아니어도 됩니다.--vault <이름>— 그 밖의 값은 이름입니다. 앱이 등록된 볼트나 폴더에 보여 주는 이름이나 별칭입니다. 대소문자는 가리지 않습니다.--vault가 없으면 현재 디렉터리를 포함하는 등록된 볼트이고, 그런 볼트가 없으면 현재 디렉터리를 포함하는 등록된 폴더입니다.
쓴 형태 하나만 시도합니다. 어느 이름과도 맞지 않는 값을 폴더로 다시 찾지 않고, 실패한 --vault가 현재 디렉터리로 넘어가지도 않습니다. 그 형태로 찾지 못하면 명령은 VAULT_NOT_FOUND로 멈춥니다. 이름에 맞는 등록된 볼트나 폴더가 둘 이상이면 VAULT_AMBIGUOUS로 멈추는데, 폴더가 지금 있는 항목만 세고 같은 폴더를 가리키는 항목은 하나로 셉니다. 이름이나 현재 디렉터리로 찾지 못했을 때는 뜻했을 만한 볼트와 폴더를 오류에 함께 나열하고, 폴더가 아닌 --vault 경로에는 아무것도 나열하지 않습니다. 앱에서 마지막으로 열려 있던 볼트로 대신하지 않습니다. 다른 곳에서 실행했을 때 엉뚱한 노트를 말없이 읽게 되기 때문입니다.
baram vaults는 등록된 것을 보여 주고, 이 오류들로 멈추지 않습니다. 정해진 볼트가 없으면 아무것도 표시하지 않은 채 등록된 볼트와 폴더를 모두 나열합니다.
현재 디렉터리가 등록된 볼트나 폴더 여럿 안에 있으면 볼트가 폴더보다 먼저이고, 볼트가 둘이면 바깥 것이 먼저입니다. 안쪽 볼트를 읽으려면 --vault를 주십시오.
| 명령 | 출력하는 것 |
|---|---|
vaults |
앱에 등록된 볼트와 폴더. *는 이 실행이 읽을 볼트의 행에 붙습니다(JSON에서는 current). 같은 폴더가 볼트로도 폴더로도 등록돼 있으면 두 행 모두에 붙습니다. |
files [--folder <경로>] |
볼트의 마크다운 파일(.md와 .markdown). |
read <경로> |
파일 하나를 디스크에 있는 그대로. UTF-8 텍스트가 아닌 파일은 IO 오류입니다. |
search <질의> [--regex] [--case-sensitive] [--word] [--folder <경로>] [--limit N] |
.md 파일에서 일치하는 곳마다 한 항목. 한 줄에 두 번 일치하면 두 번 나옵니다. --case-sensitive를 주지 않으면 대소문자를 가리지 않습니다. --word는 일치하는 곳의 양 끝에 단어 경계(\b)를 둡니다. --regex와 함께 쓰면 그 경계가 식 전체를 감싸서, a|b는 단어 a나 단어 b를 찾습니다. --limit를 주지 않으면 100건에서 멈춥니다. |
tags |
태그와 각각의 출현 횟수. |
tag <이름> |
그 태그가 달린 파일. 앞의 #는 있어도 없어도 됩니다. |
tasks [--status open|done|cancelled|all] [--file <경로>] |
태스크. 기본값 open은 todo와 doing입니다. |
backlinks <경로> |
그 노트를 가리키는 링크. |
links <경로> |
그 노트가 가진 링크와 각각이 어디로 가는지. resolved와 그 path, unresolved, 또는 otherVault와 그 볼트의 별칭으로 알려 줍니다. |
--vault와 --json은 모든 명령에 쓸 수 있고, 명령 이름 앞에 두어도 뒤에 두어도 됩니다.
경로와 줄 번호
섹션 제목: “경로와 줄 번호”read, backlinks, links, --folder, --file에 넘기는 노트나 폴더 경로는 현재 디렉터리가 아니라 볼트 루트 기준이고 /를 씁니다. 결과에 나오는 경로도 같은 방식이라, 한 명령의 출력을 다음 명령의 인자로 그대로 쓸 수 있습니다. 결과에 나오는 경로는 파일 시스템에 저장된 표기 그대로입니다. 한글이나 악센트가 있는 이름은 분해형(유니코드 NFD)으로 저장되어 있을 수 있고(macOS의 일부 도구가 그렇게 씁니다), 그러면 같은 이름을 키보드로 친 것과 바이트가 다릅니다. 링크의 이름은 어느 쪽이든 맞춥니다. backlinks와 links에서 노트에 친 [[회의록]]은 파일 시스템이 그 이름을 완성형(NFC)으로 저장했든 분해형(NFD)으로 저장했든 회의록.md를 가리킵니다. 절대 경로는 볼트 안이면 받습니다. ../로, 다른 곳의 절대 경로로, 또는 밖을 가리키는 심볼릭 링크로 볼트를 벗어나는 경로는 PATH_OUTSIDE_VAULT로 거부합니다. ..는 적힌 그대로의 경로에서 먼저 정리하고, 그 경로 안의 심볼릭 링크는 그 뒤에 따라갑니다. 그래서 read out-link/../tabs.md는 볼트의 tabs.md를 읽습니다. 셸이라면 out-link를 먼저 따라갑니다. 볼트 자신의 경로는 절대 경로입니다. JSON의 vault.path와 vaults가 나열하는 경로가 그렇습니다.
--folder는 파일, 숨김 폴더, node_modules, .git, .obsidian, .baram을 받지 않습니다. 앱이 볼트를 훑을 때 건너뛰는 폴더이고, 명령은 앱이 보는 것을 알려 줍니다. 같은 이유로 tasks --file과 links는 그 훑기가 닿는 노트만 받습니다. .md나 .markdown 파일이면서, 그 자신이 숨김 파일이 아니고 그 폴더들 안에도 없어야 합니다. 다른 파일은 INVALID_ARGUMENT로 거부합니다.
줄 번호는 1부터 셉니다.
--json이 없으면 항목 하나가 한 줄이고 필드는 탭으로 나뉩니다. 필드 안의 탭, 줄바꿈, 캐리지 리턴, 백슬래시는 \t, \n, \r, \\로 씁니다. 그 밖의 제어 문자(U+0000U+001F와 U+007FU+009F. NUL이나 터미널 색 코드를 시작하는 이스케이프 문자 같은 것)는 \u와 16진수 네 자리로, 예를 들어 \u001b로 씁니다. 한 줄에는 항목의 주요 필드만 담기고, --json에는 태스크의 날짜나 링크의 블록 ID까지 모든 필드가 담깁니다. read만 예외로, 파일 내용을 그대로 출력합니다.
--json을 주면 모든 명령이 JSON 객체 하나를 한 줄로 출력합니다. 풀어 쓰면 이런 모양입니다.
{ "vault": { "name": "Notes", "path": "/Users/me/Notes" }, "truncated": false, "items": [{ "path": "docs/guide.md", "line": 12, "snippet": "…" }]}truncated는 search가 상한보다 많이 찾아 나머지를 뺐을 때 true입니다. --json이 없으면 그 대신 결과 뒤에 표준 오류로 경고가 나옵니다. 값이 없는 필드는 빠지지 않고 null로 나옵니다. vault가 null인 경우는 볼트가 정해지지 않은 vaults뿐입니다.
항목의 순서는 정해져 있습니다. vaults는 이름 순, tags는 횟수가 많은 순에 이어 이름 순, links는 줄 순, 나머지 명령은 경로 순에 이어 줄 순입니다. 한 줄 안에서 links는 쓰인 순서와 상관없이 위키링크, 블록 임베드, 블록 참조 순으로 나열합니다.
오류와 종료 코드
섹션 제목: “오류와 종료 코드”| 종료 코드 | 뜻 |
|---|---|
0 |
성공했습니다. 결과가 비어 있어도 0이고, baram read big.md | head처럼 받는 쪽이 일찍 읽기를 멈춰도 0입니다. |
1 |
명령을 끝내지 못했습니다. 아래 오류 코드 가운데 INVALID_ARGUMENT를 뺀 전부입니다. |
2 |
명령을 잘못 썼습니다. INVALID_ARGUMENT이거나, 인자 해석기가 읽지 못하는 명령줄입니다. |
결과는 표준 출력으로, 오류와 경고는 표준 오류로 나갑니다. --json이면 명령이 알리는 오류도 한 줄짜리 JSON입니다.
{"error":{"candidates":[],"code":"FILE_NOT_FOUND","message":"no file at notes/a.md"}}--json이 없으면 같은 오류가 error[FILE_NOT_FOUND]: no file at notes/a.md로 나옵니다. 메시지도 필드처럼 이스케이프하므로 오류는 언제나 한 줄입니다. 그 아래에 후보마다 들여 쓴 한 줄(이름, 탭, 경로)이 이어집니다. message의 문구가 아니라 code로 분기하십시오.
| 코드 | 언제 | 종료 코드 |
|---|---|---|
VAULT_NOT_FOUND |
--vault에 맞는 것이 없거나, 현재 디렉터리가 등록된 어느 볼트나 폴더 안에도 없습니다. |
1 |
VAULT_AMBIGUOUS |
그 이름에 맞는 등록된 볼트나 폴더가 둘 이상입니다. 폴더가 지금 있는 항목만 세고, 같은 폴더를 가리키는 항목은 하나로 셉니다. | 1 |
PATH_OUTSIDE_VAULT |
경로가 볼트 밖으로 나갑니다. | 1 |
FILE_NOT_FOUND |
그 경로에 아무것도 없거나, 파일이 와야 할 자리에 폴더가 있습니다. | 1 |
INVALID_ARGUMENT |
명령이 받지 않는 값입니다. 예를 들어 빈 질의나 태그 이름, 잘못된 정규식, 검색 패턴이 너무 커지는 질의, 시스템이 받지 못하는 경로(너무 긴 이름), 위에서 본 대로 거부하는 폴더나 노트입니다. | 2 |
IO |
있는 것을 읽지 못했습니다. 예를 들어 권한이 없는 파일이나 폴더, UTF-8이 아닌 파일, 현재 디렉터리입니다. | 1 |
볼트를 훑는 명령은 읽지 못하는 폴더에서 IO로 멈추고, 메시지에 그 폴더를 적습니다. search는 그런 폴더를 건너뜁니다. 메시지는 영어입니다. 다만 메시지가 인용하는 것은 예외입니다. 되풀이해 적는 경로와 이름, 그리고 IO 메시지에 담긴 운영체제 자신의 실패 설명이 그렇고, Windows에서는 그 설명이 시스템 언어를 따를 것으로 봅니다(Windows에서는 아직 확인하지 않았습니다).
표준 오류에 나오는 것이 모두 이 오류는 아닙니다. 인자 해석기가 읽지 못하는 명령줄(없는 명령이나 플래그, 빠진 인자, 범위를 벗어난 값)은 --json을 읽기 전에 거절되므로, 그 메시지는 error:로 시작하는 일반 텍스트입니다(종료 코드 2). 그리고 경고는 종료 코드를 바꾸지 않습니다. 앱 설정을 읽지 못했다는 경고는 결과보다 먼저 나오고, search가 상한에서 멈췄는데 더 찾았다는 경고는 결과 뒤에, --json이 없을 때만 나옵니다. 경고는 따로 한 줄로, warning: …으로 나오며 그 메시지는 필드처럼 이스케이프합니다. --json이면 {"warning":{"message":"…"}}로 나옵니다. 환경 변수 BARAM_LOG를 설정하면 [DEBUG] cli: 5 registered roots 같은 진단 줄도 그리로 나갑니다.
앱과 다른 점
섹션 제목: “앱과 다른 점”- 저장하지 않은 편집은 보이지 않습니다. 명령은 디스크의 파일을 읽습니다.
backlinks는 백링크 패널과 같은 방식으로 셉니다. 링크는 노트를 이름으로 가리킬 수도 있고([[plan]]은 어느 폴더에 있든 이름이plan인 노트로 셉니다), 경로로 가리킬 수도 있습니다.[[notes/plan]],((notes/plan#^id)), 그 노트와 같은 폴더에서 쓴[[./plan]]이 그렇습니다.{id} {title}.md로 저장된 제텔 노트는[[id]]로도 가리킬 수 있습니다. 그 노트를 담은 등록된 볼트나 폴더의 이름을 앞에 붙인 링크도 셉니다. 그 이름은 앱에서 붙인 별칭, 그리고 저널 공간이면Journal, 제텔 공간이면Zettel입니다. 그래서 저널 공간에서는[[journal::plan]]도 셉니다. 별칭은 등록된 다른 볼트나 폴더, 파일이 같은 별칭을 갖지 않을 때만 셉니다. 공간 이름은 그 이름을 별칭으로 가진 볼트나 폴더, 파일이 등록돼 있지 않고 같은 종류의 다른 공간도 등록돼 있지 않을 때만 셉니다. 별칭이 공간 이름보다 앞서므로, 별칭이journal인 볼트에서는 저널 공간이 따로 등록돼 있어도[[journal::plan]]을 셉니다. 접근을 승인하지 않은 볼트, 폴더, 파일은 앱처럼 빼고 봅니다. 노트를 담지 않은 볼트의 이름을 붙인 링크는 세지 않습니다. 한 줄에 그 노트로 가는 링크가 여럿이면 한 번만 알려 줍니다. 아직 없는 노트는 물어볼 수 있지만 폴더는 물어볼 수 없습니다. 등록된 볼트나 폴더가 겹쳐 있으면 패널은 그 노트를 담은 것마다 그 색인에 묻고 답을 합치므로, 이번 실행이 고른 볼트 하나만 읽는 이 명령보다 더 많이 보일 수 있습니다. 노트에만 쓰십시오.papers/Paper.pdf같은 다른 파일은[[papers/Paper.pdf]]는 세지만, 경로 없는 이름은 확장자를 뺀 이름으로 찾기 때문에[[Paper]]는 세고[[Paper.pdf]]는 세지 않습니다.links와는 반대입니다.links는 클릭이 아니라 그래프 뷰가 푸는 방식으로 풉니다. 링크의 경로는 볼트 루트에서만 따라갑니다.[[./plan]]이나 아무 데도 닿지 않는 경로는 마지막 이름으로 찾고, 그 이름의 노트가 어디에 있든 그리로 갑니다. 그래서 상대 경로 링크에서는 두 명령의 답이 갈릴 수 있습니다.b/에서 쓴[[./plan]]은b/plan.md의 백링크인데links는 그 링크를a/plan.md로 풀 수 있고, 아무 데도 닿지 않는 상대 경로 링크는 그 경로에 아직 없는 노트의 백링크로만 셉니다. 저널 날짜도 따로 다루지 않습니다. 다른 볼트로 가는 링크는otherVault와 그 별칭으로 알려 주는데, 그래프 뷰는 그 링크를 같은 이름의 로컬 노트로, 그런 노트가 없으면 자리표시 노드로 긋습니다. 볼트 자신의 이름을 붙인 링크(저널 공간의[[journal::plan]])도otherVault로 알려 주는데,backlinks는 그 링크를 셉니다.links는 이번 실행이 고른 볼트의 색인을 읽습니다. 등록된 폴더가 볼트 안에 있으면 앱의 그래프는 그 폴더 자신의 색인을 쓰므로, 같은 이름의 노트가 둘일 때 결과가 다를 수 있습니다.tasks는 볼트 하나를 읽습니다. 태스크 패널은 범위 설정에 따라 여러 볼트를 보일 수 있습니다. 앱 설정에서 태스크에서 제외한 폴더는 여기서도 제외됩니다. 그런 폴더 안의 노트에tasks --file을 쓰면 오류 없이 태스크를 하나도 출력하지 않습니다.search는.md파일만 읽습니다. 다른 명령은.markdown도 읽습니다. 또search는notes/.draft.md처럼 일반 폴더 안의 숨김 파일도 읽는데,files는 그런 파일을 나열하지 않습니다.backlinks와links는 부를 때마다 볼트의 링크를 색인합니다. 노트 10,000개에 0.5초가 조금 안 걸립니다(Apple M5 Pro, 릴리스 빌드, 웜 캐시에서 측정).
AI 에이전트에게 알려 주기
섹션 제목: “AI 에이전트에게 알려 주기”명령이 어디 있는지와 읽기 전용이라는 점을 에이전트에게 알려 주십시오. 예를 들어 Mac에서는 프로젝트의 CLAUDE.md에 이렇게 적습니다.
My notes are a Baram vault at ~/Notes. Query them with Baram's read-only CLI,/Applications/Baram.app/Contents/MacOS/baram — call it by that full path(it is shortened to `baram` below).
- `baram --vault ~/Notes --json search "<text>"` — find notes- `baram --vault ~/Notes read <path>` — read one- `baram --vault ~/Notes --json backlinks <path>` — what links to it- `baram --vault ~/Notes --json tasks` — open tasks
Paths are relative to the vault root. Exit code 0 with no items means "nothing found";1 or 2 is an error, reported on standard error.Linux에서 .deb 패키지로 설치했다면 baram이 이미 PATH에 있으므로 전체 경로가 필요 없습니다.
Claude Desktop처럼 명령을 실행하지 못하는 채팅 클라이언트에는 같은 명령이 MCP 서버의 도구로 있습니다.

