Markdown에 설명도 코드도 직접 쓰면 되지 않을까 생각해서 CLI를 만들었다
요약
mds(Markdown Source)는 Markdown 파일을 단순한 설명문이 아닌, 목적, 제약 조건, 실제 코드를 모두 포함하는 '구현 문서'로 활용하는 개발 도구입니다. 이 도구는 사용자가 작성한 Markdown 내의 특정 코드 블록을 추출하여 일반적인 소스 파일(.ts, .py 등)로 자동 생성합니다. 이를 통해 설계 문서와 구현 코드가 분리되어 관리되는 문제를 해결하고, 특히 AI 코딩 에이전트 환경에서 목적과 제약 사항을 코드 근처에 유지할 수 있도록 돕습니다.
핵심 포인트
- mds는 Markdown 내의 코드 블록 자체를 실행 가능한 소스 코드로 변환하는 CLI 도구입니다.
- 기존 방식처럼 문서와 코드가 분리되어 관리되는 문제를 해결하고, 문서를 '설명'과 '구현'을 함께 담는 파일로 사용합니다.
- `.mds/source/` 디렉토리는 구현 로직(Purpose, Contract, Source 등)을 정의하며 `src/` 폴더를 생성하는 데 사용됩니다.
- `.mds/test/` 디렉토리는 테스트 케이스와 실제 테스트 코드를 작성하여 검증 가능한 환경을 제공합니다.
- 코드 수정 시에는 생성된 파일이 아닌 원본 Markdown 문서(`.mds/source/*.md`)를 직접 수정해야 합니다.
서론
설명문과 실제 코드를 동일한 Markdown에 모아서, 거기서부터 실행 가능한 소스 코드를 생성하는 CLI로서 mds를 만들고 있습니다.
리포지토리는 여기입니다.
이 기사에서는 mds가 무엇을 하는 도구인지, 어떤 구성으로 사용하는지를 간단히 소개합니다.
mds란
Markdown Source의 약자입니다.
mds는 Markdown을 단순한 설명문이 아니라, 설명문과 실제 코드를 함께 가지는 "구현 문서 (Implementation Document)"로 취급하는 개발 도구입니다.
Markdown 안에는 목적이나 제약 등의 설명뿐만 아니라, TypeScript, Python, Rust 등의 실제 코드도 작성합니다.
mds build는 해당 코드 블록을 추출하여 일반적인 .ts, .py, .rs 파일로 생성합니다.
예를 들어, 다음과 같은 흐름입니다.
.mds/source/add.ts.md
↓ mds build
src/add.ts
즉, mds는 "설명을 쓴 옆에 코드 예시를 두는 것"이 아니라, Markdown 안에 있는 코드 블록 자체가 생성 후의 소스 코드가 됩니다.
AI가 설명문을 읽고 분위기로 코드를 만드는 것이 아닙니다.
mds는 Markdown 내의 코드 블록과 메타 정보를 읽어서, 정해진 규칙에 따라 파일을 생성합니다.
왜 만들었는가
AI 주도 (AI-driven) 개발을 할 때, 처음에는 README나 설계 문서에 목적을 작성하고 그 후에 구현으로 넘어갑니다. 하지만 시간이 지나면 코드만 올바르게 유지되고, 문서만 낡아버리는 경우가 자주 발생합니다.
mds에서는 이러한 차이를 줄이기 위해 Markdown 안에 다음 정보를 모읍니다.
- 무엇을 위한 코드인가
- 어떤 동작을 준수해야 하는가
- 무엇을 공개하는가
- 무엇에 의존하는가
- 실제 구현 코드
- 테스트 코드
즉, Markdown을 "설명"과 "구현"을 함께 두기 위한 파일로 사용합니다.
특히 AI 코딩 에이전트 (AI Coding Agent)를 사용하는 경우, 코드뿐만 아니라 목적이나 제약 사항도 가까이 두고 싶습니다.
mds는 이를 위한 형태를 시도하는 도구입니다.
기본 구성
mds에서는 주로 .mds/ 하위에 Markdown을 둡니다.
my-package/
mds.config.toml
.mds/
...
여기서 중요한 것은 .mds/source/와 .mds/test/의 역할이 다르다는 점입니다.
| 디렉토리 | 역할 | 주요 섹션 | 생성 대상 예시 |
|---|---|---|---|
.mds/source/ | 구현을 작성함 | Purpose, Contract, Exports, Imports, Source | src/add.ts |
.mds/test/ | 테스트를 작성함 | Purpose, Covers, Imports, Cases, Test | tests/add.test.ts |
.mds/source/는 구현용입니다.
따라서 중심이 되는 것은 Source 섹션입니다.
.mds/test/는 테스트용입니다.
따라서 기대하는 동작을 Cases에 작성하고, 실제 테스트 코드를 Test 섹션에 작성합니다.
구현 Markdown 예시
여기서는 간단한 add 함수의 예로 설명하겠습니다.
먼저, 구현용 Markdown을 만듭니다.
.mds/source/add.ts.md
내용은 다음과 같이 합니다.
# add
## Purpose
2개의 수치를 더하는 함수를 제공한다.
...
```ts
export function add(a: number, b: number): number {
return a + b;
}
이 파일은 설명문과 실제로 생성될 TypeScript 코드를 함께 가지는 구현 문서입니다.
`Purpose`에는 목적을 작성합니다.
`Contract`에는 준수해야 할 동작을 작성합니다.
`Exports`에는 외부에 공개할 함수나 타입을 작성합니다.
`Imports`에는 의존 관계를 작성합니다.
`Source`에는 실제 TypeScript 코드를 작성합니다.
이 Markdown으로부터 `mds build`를 실행하면 `src/add.ts`가 생성됩니다.
// Generated by mds. Do not edit. Source: .mds/source/add.ts.md. Source-Hash: <sha256>.
export function add(a: number, b: number): number {
return a + b;
...
생성된 `src/add.ts`는 구현 문서 내의 `Source` 섹션으로부터 만들어진 파일입니다.
수정하고 싶은 경우에는 `src/add.ts`를 직접 수정하는 것이 아니라, `.mds/source/add.ts.md`를 고친 후 다시 생성합니다.
## 테스트 Markdown 예시
다음으로, 테스트용 Markdown을 만듭니다.
.mds/test/add.test.ts.md
내용은 다음과 같이 합니다.
add test
Purpose
add가 두 숫자를 올바르게 더하는지 확인한다.
...
import { describe, expect, it } from "vitest";
import { add } from "../src/add";
describe("add", () => {
it("adds two numbers", () => {
expect(add(1, 2)).toBe(3);
expect(add(0, 5)).toBe(5);
expect(add(-1, -2)).toBe(-3);
});
});
테스트 Markdown에서는 `Cases`와 `Test`를 나누어 작성할 수 있습니다.
`Cases`는 사람이나 AI가 기대하는 동작을 읽기 쉽게 만들기 위한 표입니다.
`Test`는 실제로 생성되는 테스트 코드입니다.
이 Markdown으로부터 `mds build`를 실행하면 `tests/add.test.ts`가 생성됩니다.
## mds build
Markdown으로부터 소스 코드 (Source Code)를 생성하려면 `mds build`를 사용합니다.
mds build --package ./my-package
갑자기 작성하는 것이 두렵다면, 먼저 `--dry-run`으로 차이점 (diff)을 확인할 수 있습니다.
mds build --package ./my-package --dry-run
`mds`가 생성하는 파일에는 관리 헤더 (Management Header)가 붙습니다.
Generated by mds. Do not edit. Source: <path>. Source-Hash: <sha256>.
이 헤더를 통해 `mds`가 관리하고 있는 생성 파일인지 여부를 판단할 수 있습니다.
관리 헤더가 없는 기존 파일이 생성 위치에 있는 경우, `mds`는 안전을 위해 덮어쓰지 않습니다.
수기로 작성한 파일을 실수로 망가뜨리지 않기 위해서입니다.
생성 결과는 `.mds/manifest.toml`에도 기록됩니다.
## mds lint / typecheck / test
`mds`에는 생성 이외의 명령어도 있습니다.
mds lint --package ./my-package
mds typecheck --package ./my-package
mds test --package ./my-package
`mds lint`는 Markdown의 구조, 표, 설정, 생성 위치 등을 검사합니다.
또한, 설정되어 있는 경우 Markdown 내의 코드 블록 (Code Block)에 대해 언어별 lint도 실행합니다.
`mds typecheck`는 TypeScript나 Python 등의 타입 검사 (Type Check)로 연결합니다.
`mds test`는 테스트 Markdown의 `Test` 섹션에 작성한 코드를 대상으로 언어별 테스트 러너 (Test Runner)를 실행합니다.
## mds init
`mds init`은 `mds`를 사용하기 위한 초기화 명령어입니다.
mds init
인수 없이, 또는 `--package`만으로 실행하면 대화 형식의 TUI 위저드 (Wizard)가 시작됩니다.
mds init --package ./my-package
위저드에서는 예를 들어 다음과 같은 항목을 차례대로 선택합니다.
- 표시 레이블의 언어
- 대상 패키지
- 검출된 툴체인 (Toolchain)
- typecheck / lint / test 명령어
- AI Kit를 생성할지 여부
- 어떤 AI CLI를 대상으로 설정을 생성할지
`package.json`, `pyproject.toml`, `Cargo.toml` 등과 같은 메타데이터가 있는 경우, 이를 참조하여 후보를 제시합니다.
플래그를 통해 한꺼번에 지정할 수도 있습니다.
mds init
--package ./my-package
--ts-tools biome,vitest
...
사용하지 않는 언어나 검사는 `none`으로 무효화할 수 있습니다.
mds init --package ./my-package --ts-tools none --py-tools pytest --rs-tools none
## AI 에이전트용 설정 생성
`mds init --ai`를 사용하면, AI 코딩 에이전트 (AI Coding Agent)용 설정 파일도 생성할 수 있습니다.
mds init --ai --target all --categories all
실제로 파일을 작성할 때는 `--yes`를 붙입니다.
mds init --ai --target all --categories all --yes
지원하는 대상은 다음과 같은 AI CLI입니다.
| 대상 | 생성 위치 예시 |
|---|---|
| Claude Code | `.claude/rules/` , `.claude/skills/` , `.claude/commands/` |
| Codex CLI | `.codex/instructions.md` , `.codex/skills/` |
| Opencode | `.opencode/agents/` , `.opencode/skills/` |
| GitHub Copilot | `.github/instructions/` , `.github/prompts/` |
생성되는 설정에는 `mds`의 Markdown 포맷, 섹션 구조, 제약 사항 등이 포함됩니다.
AI 에이전트에게 "이 프로젝트에서는 Markdown으로부터 구현을 생성한다"라는 전제를 전달하기 위한 메커니즘입니다.
## VS Code 확장과 LSP
`mds`에는 `mds-lsp`도 있습니다.
VS Code 확장은 다음 명령어로 설치할 수 있습니다.
code --install-extension owo-x-project.mds
VS Code 확장에는 대응하는 `mds-lsp` 바이너리가 동봉되어 있습니다.
Markdown 안에 구현을 작성하는 경우, 에디터 측의 지원이 중요합니다.
일반적인 Markdown과 달리 섹션 구조, 코드 블록, 의존 관계, 생성 위치 등을 의식해야 하기 때문입니다.
## 무엇이 좋은가
`mds`를 사용하면 설계 메모와 구현 사이의 거리를 좁힐 수 있습니다.
코드만 보면 왜 그런 형태로 만들었는지 알기 어려울 때가 있습니다.
Markdown만 보면 구현과 어긋나 있을 때가 있습니다.
`mds`에서는 목적, 제약, 공개 인터페이스, 의존 관계, 구현 코드를 동일한 Markdown에 둡니다.
따라서 다음과 같은 상태를 지향할 수 있습니다.
- 구현 의도를 코드 근처에 남길 수 있음
- 의존 관계를 Markdown 상에서 보기 쉽게 만들 수 있음
- 테스트 의도와 테스트 코드를 가까이 둘 수 있음
- AI 에이전트에게 전달할 컨텍스트 (Context)를 정리하기 쉬움
비슷한 개념으로 문예적 프로그래밍 (Literate Programming)이 있습니다.
문예적 프로그래밍은 인간이 읽기 쉬운 설명을 중심으로, 프로그램을 하나의 문장처럼 구성하는 사고방식입니다.
`mds`도 설명문과 실제 코드를 같은 장소에 둔다는 점에서는 유사합니다.
다만, `mds`는 읽을거리로서 아름다운 프로그램을 쓰는 것보다, Markdown을 인간·CLI·AI 에이전트가 공통적으로 다룰 수 있는 구현 문서로 만드는 것을 중시합니다.
즉, `mds`는 문예적 프로그래밍 그 자체라기보다, AI 코딩 에이전트 시대에 맞춰 설명문·실제 코드·테스트·의존 관계를 구조화하기 위한 시도입니다.
## 적합해 보이는 용도
현시점에서는 다음과 같은 용도에 적합하다고 생각합니다.
- 작은 CLI
- 작은 라이브러리
- 실험적인 도구
- AI 에이전트에게 작업을 시키는 것을 전제로 한 프로젝트
- 설계 의도를 강하게 남기고 싶은 코드베이스
반대로, 기존의 대규모 프로젝트에 갑자기 전면 도입하는 것은 아직 이릅니다.
우선은 작은 프로젝트나 일부 모듈에서 시도하는 것이 안전하다고 생각합니다.
## 현시점의 과제
아직 알파 버전이므로 과제는 있습니다.
- 사양(Specification)이 변경될 가능성이 있음
- 실제 운용 사례가 적음
- Markdown 작성 방식에 익숙해질 필요가 있음
- 기존 프로젝트에 도입하는 흐름은 아직 정리가 필요함
- 어디까지 Markdown에 의존할 것인지, 운용 패턴을 늘릴 필요가 있음
특히, Markdown 안에 구현을 작성하는 형태는 일반적인 개발 흐름과는 조금 다릅니다.
따라서 갑자기 크게 사용하기보다, 작게 시도하며 감을 익히는 것이 좋아 보입니다.
## 마치며
`mds`는 Markdown을 '설명문과 실제 코드를 함께 가지는 구현 문서'로 다루기 위한 실험적인 CLI입니다.
설명, 제약, 의존 관계, 구현, 테스트를 Markdown에 정리하고, 거기서 일반적인 소스 코드를 생성합니다.
AI 코딩 에이전트를 사용하는 기회가 늘어날수록, 코드 그 자체뿐만 아니라 코드 주변에 있는 문맥(Context)도 중요해질 것이라고 생각합니다.
`mds`는 그 문맥을 Markdown으로서 다루기 쉽게 만들기 위한 시도입니다.
관심이 있다면 리포지토리를 확인해 주시면 감사하겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기