diff --git a/README.md b/README.md index 189bf09..5d34109 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,13 @@ git tag v0.2.0 && git push --tags # PreToolUse 훅이 명시적 승인 없 --- +## About / 프로젝트 회고 + +이 프로젝트가 **어떤 문제를 해결하려 했는지**, **어떻게 구현했는지**, **구현 과정에서 내린 결정**, **자체 평가**를 정리한 회고는 [docs/portfolio.md](docs/portfolio.md)에 있습니다. + +이 프로젝트는 클로드 코드의 도움을 받아 작성되었습니다. +--- + ## 라이선스 MIT — [LICENSE](LICENSE) 참조. diff --git a/docs/portfolio.en.md b/docs/portfolio.en.md new file mode 100644 index 0000000..8e48737 --- /dev/null +++ b/docs/portfolio.en.md @@ -0,0 +1,184 @@ +# Ossmate — Portfolio Retrospective + +**One-liner**: An open-source CLI + Claude Code plugin that automates the repetitive work of OSS maintainers by combining all 12 Claude Code extension surfaces. + +- **Repo**: [github.com/sunjin12/ossmate](https://github.com/sunjin12/ossmate) +- **Distribution**: PyPI (`ossmate`, `ossmate-mcp`), Claude Code plugin marketplace +- **Scale**: Python 3.11+, 176 tests (pytest, ~5s), 3-OS × 3-Python CI matrix, 10 phase tags +- **Duration**: Incremental self-build from Phase 0 to v0.1.0; still self-dogfooding through v0.1.x patches (PR #1~#4) +- **Solo project** (spec, design, implementation, release, maintenance — all by one person) + +--- + +## 1. What Problem Was I Solving? + +### Primary — Repetitive maintainer operations + +Beyond their core work (features, reviews), solo maintainers are drained by **repetitive, attention-taxing operational chores**: + +| Task | Friction without Ossmate | +|---|---| +| PR triage | Read diff / commits / CI and judge scope/risk/mergeability by hand, every PR | +| Issue classification | Manually label every incoming issue as bug/feature/docs/duplicate/… | +| Release notes | Scrape commits since the last tag and re-format into Keep-a-Changelog | +| Dependency audit | Re-assemble lockfile parsing + OSV advisory lookup every time | +| Stale-issue sweep | Find issues idle for 60+ days and decide nudge vs. close | +| Contributor onboarding | Hand-write welcome messages for each first-time contributor | + +The work is **patterned but still requires judgment per case** — neither fully automatable nor efficient to do manually. A perfect niche for LLM assistance. + +### Secondary — Learning the Claude Code extension surfaces + +Claude Code exposes 12 extension points (Skills, Subagents, Hooks, MCP, Plugin, Agent SDK, Scheduled triggers, Status line, Output styles, Memory, Settings, Keybindings), but **there were few examples integrating all of them into a single coherent product**. To really feel what each surface contributes to a real domain, the fastest path is to build it yourself. + +→ **Ossmate is designed to serve both purposes at once**: a practical tool, and a reference implementation of Claude Code. + +--- + +## 2. How I Built It + +### Design principle: 10 phases, each independently demoable + +| Phase | Deliverable | +|---|---| +| 0 | Skeleton (pyproject × 2, CLAUDE.md, settings.json) | +| 1 | Output style + status line — **immediate visual feedback** | +| 2 | First Skill `/triage-issue` — Bash-only, pre-MCP | +| 3 | 5 Hooks (including PreToolUse guard) | +| 4 | MCP server — 11 tools + 3 resource templates | +| 5 | 6 Subagents (haiku/sonnet/opus tiering) + remaining skills refactored to delegate | +| 6 | Plugin packaging + self-hosted `marketplace.json` | +| 7 | Standalone CLI — reloads `.claude/commands/*.md` bodies so one skill powers both slash + subcommand | +| 8 | Scheduled triggers (daily digest, weekly stale sweep, Friday release radar) | +| 9 | CI/CD 3-OS × 3-Python matrix + OIDC PyPI publishing → v0.1.0 cut | + +Each phase is tagged `phase-N`, so `git checkout phase-5` shows the snapshot at that point. **Any phase boundary is a shippable demo** — a guardrail against scope creep. + +### Architecture + +``` +User ─┬─ /slash commands ──► Claude Code ──► Skills ──► Subagents ──► MCP ──► GitHub API + └─ ossmate CLI ─────► Agent SDK ────────────────────────────┘ OSV.dev + Local repo +``` + +**The same MCP server backs both the plugin and the standalone CLI** → tools (gh calls, OSV queries, lockfile parsing) are written once and reused everywhere. + +### Why each surface + +Every one of the 12 surfaces is justified by **what friction appears when it's missing** ([README.md:111-130](../README.md#L111-L130) table). Not a contrived demo mapping; each plays a real role in actual use: + +- **Subagent model tiering** — Haiku for bulk issue classification, Opus for security review, Sonnet for PR triage. Cost/speed optimization vs. a one-size-fits-all model. +- **PreToolUse Hook guard** — Blocks destructive commands like `git push origin main`, `gh pr merge`, `gh release create` before they run. Later, when I tried to merge a PR myself, this hook stopped me — proving self-dogfooding works. +- **MCP vs. inline scripts** — Keeping gh/OSV/lockfile logic in MCP lets Claude Code, the CLI, and other AI clients reuse it. +- **Plugin vs. CLI** — Plugin is installable instantly for Claude Code users; CLI targets CI / remote shells / non-Claude-Code environments. A shared skill body avoids double maintenance. + +--- + +## 3. Problems and Decisions Along the Way + +### 3.1 Scope decision — "Do we really use all 12 surfaces?" + +Early trade-off: Skills + MCP alone would have made a working tool. Were 12 surfaces excessive? + +**Decision**: Use all surfaces — but each one must earn its place by removing a **specific friction**, not exist "for the sake of being there". Keybindings are explicitly labeled the lowest-value surface in the README table. If a surface can't be justified, it shouldn't be added. + +**Why**: Portfolio value (reference implementation) + learning value (feeling each surface's real constraints) + reuse design (a shared MCP makes adding surfaces easier, not harder). + +### 3.2 Plugin ↔ Standalone CLI duplication + +Supporting both would normally mean duplicating slash-command bodies and CLI prompt bodies — a maintenance nightmare. + +**Decision**: Treat `.claude/commands/*.md` as the single source of truth; the CLI loads markdown bodies from disk directly and feeds them to `ClaudeAgentOptions`. One skill written → slash command + CLI subcommand for free. `test_no_orphan_subcommands` enforces the invariant. + +**Consequence**: When `doctor` was added in Phase 7 as CLI-only (no matching slash command), an explicit whitelist `cli_only_allowlist = {"version", "doctor"}` was added to make the exception visible. + +### 3.3 Windows cp949 locale + +During `doctor` implementation, `subprocess.run(text=True)` threw `UnicodeDecodeError` in cp949 locales — invisible on macOS/Linux CI. + +**Decision**: Make every subprocess call pass `encoding="utf-8", errors="replace"` explicitly. Hook-script conventions are separately saved as a "Windows environment constraint" memory to avoid relearning the same lesson. + +### 3.4 CI was red for 3 commits and I didn't notice + +After the `phase-9` merge, `test_referenced_hook_scripts_exist` was failing on Linux/macOS but passing locally on Windows (pathlib swallowed the trailing backslash). With no notification pipeline, I pushed 3 more commits before the `doctor` PR surfaced the failure. + +**Decision**: +1. Immediate fix: regex `[^\"]+` → `[^\"\\]+` (excludes trailing backslash) +2. Bundle pre-existing lint errors (24 total) into the same PR — restore green in a single bar +3. Save a memory note: "CI failure notification pipeline needed" → queued as top v0.1.x candidate + +**Lesson**: A multi-OS matrix alone isn't enough — you also need a **channel that tells you when it breaks** (planning Slack webhook or badge monitoring next iteration). + +### 3.5 Blocked by my own PreToolUse hook (self-dogfooding) + +When merging PR #3, I tried `gh pr merge` — and the PreToolUse guard I built in Phase 3 responded: `gh pr merge is denied. Merge through the GitHub UI after maintainer review.` + +**Decision**: Don't bypass. User merged via GitHub UI instead. → **Live proof that the project's security policy actually works**. Recorded in the CHANGELOG and this retrospective. + +### 3.6 Scoping `ossmate doctor` (after evaluation) + +Post-Phase-9 review identified "onboarding friction" as a medium-severity weakness. Three candidates: + +| Candidate | Scope | Risk | +|---|---|---| +| Eval suite | Large (2~3 days) | Scope blowup | +| Hygiene bundle (templates, etc.) | Small (30 min) | Low impact | +| **`ossmate doctor`** (chosen) | Medium (2~3 hours) | Right-sized | + +**Rationale**: Self-diagnoses ~80% of common failure modes (gh missing, wrong directory, broken MCP install) with a single command. Zero new dependencies (reused existing `rich`). Scope pinned at 6 checks × ≥5 tests. → Merged as PR #3. + +### 3.7 Dead-link cleanup (PR #4) + +A `docs/architecture.md` link existed in README, but the file didn't (user flagged it). Two other phase-doc links were pointing into memory paths (`memory/project_phases.md`) that also didn't exist. + +**Decision**: Instead of creating a new file for the architecture link, inline the 12-surface justification table into README. Phase descriptions had genuine public-doc value, so materialize them at `docs/project_phases.md`. As a byproduct, relaxed the "no new markdown design docs" rule in `.claude/CLAUDE.md` to explicitly permit public explainers under `docs/`. + +**Lesson**: Dead links in a public repo hit recruiter credibility directly → small docs hygiene matters as much as the implementation work. + +--- + +## 4. Self-Assessment + +### What went well + +- **Scope discipline**: A 10-phase plan that actually shipped in 10 phases — no mid-flight ambition-creep before cutting v0.1.0. `[Unreleased]` convention keeps v0.1.x iterations clean. +- **Self-dogfooding**: Ossmate runs on its own repo. The hook stopped me, scheduled triggers run daily digests here, the CHANGELOG is written by Ossmate itself. Meta-consistency. +- **Test density**: 176 hermetic tests, ~5s. Rule: every new feature adds ≥5 tests. Pre-existing bugs fixed in the same PR, so CI stays green. +- **Cross-platform**: Developed on Windows, verified on Linux/macOS CI. cp949 encoding, path separators, hook execution conventions — all addressed explicitly. +- **OIDC publishing**: Zero PyPI tokens stored as secrets. Release by pushing a tag; the workflow rejects if tag version ≠ pyproject version. +- **Security policy proven in the wild**: The PreToolUse hook actually blocked my own `gh pr merge` — confirmation that the policy isn't just theater. + +### What's weak + +- **CI notification gap**: Main was red for 3 commits without being noticed. No badge / Slack / email pipeline yet. Top priority for next iteration. +- **Onboarding friction**: `doctor` mitigates ~80%, but users still need `pipx` + `gh auth` + MCP install. Multi-step for newcomers. +- **Zero real users yet** (besides me): Up through Phase 9 was a build cycle; it only went fully public post-v0.1.x. No adoption data yet → hard to measure real-world value. +- **Keybindings surface**: The weakest link among the 12. Honestly labeled "lowest value" in the README, but inclusion itself is worth revisiting. +- **Actions version drift** (e.g. Node.js 20 deprecation): No Dependabot config yet → manual vigilance required when the deprecation window arrives. + +### What I learned + +1. **Clarifying "what friction am I removing" matters more than building the tool.** Each surface's inclusion was decided by its friction-removal role rather than "I want to learn it" — and that decision drove the overall coherence. +2. **Investing in a shared data source (MCP) pays off.** Supporting both a plugin and a CLI didn't cost 2×, because both sit on the same MCP. +3. **Self-dogfooding makes bugs surface themselves.** When a hook blocks *me*, I know the policy is alive. +4. **The "independently demoable phase" principle kept scope creep in check** and also kept morale up — any phase boundary is a shippable milestone. +5. **Windows-dev + Linux-CI is not free.** Invisible-on-local failures require both a multi-OS matrix *and* a notification pipeline (the latter is still missing). +6. **Understanding the domain matters more than I thought.** Claude Code recommended the "OSS maintainer support" project for harness-programming practice, but my lack of background in actually maintaining OSS made development feel like outsourced work. Next project: build domain knowledge of the target field *first*, then start building. + +### Next v0.1.x roadmap candidates + +- CI failure notification pipeline (Slack webhook / email / badge audit) +- Dependabot + Node.js 20 → bump actions versions +- PR / Issue templates (under `.github/`) +- Expand `doctor` checks based on real user feedback (git-lfs, Node version, plugin marketplace sync) +- Eval suite — catch skill-output quality regressions + +--- + +## Related docs + +- [README](../README.md) — Quickstart, per-surface value +- [docs/project_phases.md](project_phases.md) — 10-phase detailed plan +- [CHANGELOG](../CHANGELOG.md) — Version history (generated by Ossmate itself) +- [CONTRIBUTING](../CONTRIBUTING.md) — Dev setup / commit conventions diff --git a/docs/portfolio.md b/docs/portfolio.md new file mode 100644 index 0000000..73df04b --- /dev/null +++ b/docs/portfolio.md @@ -0,0 +1,185 @@ +# Ossmate — 포트폴리오 요약 + +**한 줄 소개**: Claude Code의 12개 확장 표면을 모두 결합해 OSS 메인테이너의 반복 업무를 자동화한 오픈소스 CLI + 플러그인. + +- **저장소**: [github.com/sunjin12/ossmate](https://github.com/sunjin12/ossmate) +- **배포**: PyPI (`ossmate`, `ossmate-mcp`), Claude Code 플러그인 마켓플레이스 +- **규모**: Python 3.11+, 176개 테스트(pytest, ~5s), 3-OS × 3-Python CI 매트릭스, 10개 phase 태그 +- **기간**: Phase 0 → v0.1.0 까지 단계적 자체 빌드, v0.1.x 패치(PR #1~#4)까지 self-dogfooding 중 +- **1인 프로젝트** (기획·설계·구현·배포·유지보수 전 과정) + +--- + +## 1. 어떤 문제를 해결하려 했는가 + +### 1차 문제 — OSS 메인테이너의 반복 업무 + +솔로 메인테이너는 본업(기능 개발, 리뷰) 외에 **반복적이고 집중력을 갉아먹는 운영 업무**에 시간을 뺏긴다: + +| 업무 | Ossmate 없을 때의 마찰 | +|---|---| +| PR 트리아지 | PR 하나당 diff·커밋·CI 읽고 scope/risk/mergeability 판단을 매번 수동 | +| 이슈 분류 | 받은 이슈를 bug/feature/docs/duplicate 등으로 라벨링하는 반복 | +| 릴리스 노트 작성 | 직전 태그 이후 커밋을 긁어 Keep-a-Changelog 포맷으로 재가공 | +| 의존성 감사 | lockfile 파싱 + OSV advisory 조회 스크립트를 매번 재구성 | +| Stale 이슈 정리 | "60일 넘게 대기 중인 이슈"를 찾아 nudge/close 결정 | +| 컨트리뷰터 온보딩 | 첫 기여자에게 보낼 환영 메시지를 매번 수동 작성 | + +이 업무들은 **패턴은 반복되지만 개별 판단이 필요**해서 완전 자동화도, 완전 수동도 비효율적이다. LLM이 보조하기에 적합한 지점. + +### 2차 문제 — Claude Code 확장 표면 학습 + +Claude Code는 12개의 확장 지점(Skills, Subagents, Hooks, MCP, Plugin, Agent SDK, Scheduled triggers, Status line, Output styles, Memory, Settings, Keybindings)을 제공하지만, **이들을 단일 제품 안에서 통합해 운영한 사례가 부족**했다. 각 표면이 실제 도메인 문제에 어떤 가치를 더하는지 체감하려면 직접 만들어보는 것이 가장 빠르다고 판단. + +→ **Ossmate는 "실용 도구"와 "Claude Code 레퍼런스 구현체" 두 목적을 동시에 충족하도록 설계**했다. + +--- + +## 2. 어떻게 구현했는가 + +### 설계 원칙: 10단계, 각 단계는 독립 시연 가능 + +| Phase | 성과물 | +|---|---| +| 0 | Skeleton (pyproject × 2, CLAUDE.md, settings.json) | +| 1 | Output style + status line — **즉각적 시각 피드백** | +| 2 | 첫 Skill `/triage-issue` — Bash-only, MCP 전 단계 | +| 3 | 5개 Hook (PreToolUse guard 포함) | +| 4 | MCP 서버 — 11 tools + 3 resource templates | +| 5 | 6개 Subagent (haiku/sonnet/opus 티어링) + 나머지 Skill 리팩터 | +| 6 | Plugin 패키징 + 자체 marketplace.json | +| 7 | 독립 CLI (`.claude/commands/*.md` 본문을 CLI가 재로딩 → 1회 작성으로 slash+subcommand 동시 지원) | +| 8 | Scheduled triggers (daily digest, weekly stale sweep, Friday release radar) | +| 9 | CI/CD 3-OS × 3-Python 매트릭스 + OIDC PyPI 발행 → v0.1.0 cut | + +각 phase는 `phase-N` 태그로 마킹되어 `git checkout phase-5`로 당시 스냅샷을 볼 수 있다. **어느 phase에서 멈춰도 독립 데모가 가능**하게 설계 — 스코프가 터지는 것을 방지. + +### 아키텍처 + +``` +User ─┬─ /slash commands ──► Claude Code ──► Skills ──► Subagents ──► MCP ──► GitHub API + └─ ossmate CLI ─────► Agent SDK ────────────────────────────┘ OSV.dev + Local repo +``` + +**같은 MCP 서버가 Plugin과 CLI 양쪽을 백엔드로 지원** → 도구(gh 호출, OSV 조회, lockfile 파싱)를 1회 구현하면 모든 진입점에서 재사용. + +### 표면별 선택 근거 + +12개 표면 각각이 "없을 때 어떤 마찰이 생기는지"로 정당화 ([README.md:111-130](../README.md#L111-L130) 표). 데모용 끼워 맞추기가 아니라 실제 사용 시나리오에서의 역할을 기준으로 함: + +- **Subagents 모델 티어링** — bulk 이슈 분류는 Haiku, 보안 리뷰는 Opus, PR 트리아지는 Sonnet. 단일 모델 사용 대비 비용/속도 최적화. +- **Hooks PreToolUse guard** — `git push origin main`, `gh pr merge`, `gh release create` 등 파괴적 명령을 사전 차단. 나중에 내가 PR을 머지하려 했을 때 이 훅이 나를 막아서 self-dogfooding이 증명됨. +- **MCP vs 인라인 스크립트** — gh/OSV/lockfile 로직을 MCP에 두면 Claude Code/CLI/다른 AI 클라이언트 모두에서 재사용 가능. +- **Plugin vs CLI** — Plugin은 Claude Code 사용자에게 즉시 설치 가능, CLI는 CI/원격 shell/non-Claude-Code 환경용. 공통 skill body를 공유해 이중 유지보수 회피. + +--- + +## 3. 구현 과정의 문제와 결정 + +### 3.1 "모든 표면을 쓸 것인가" 스코프 결정 + +초기에 고민: Skills + MCP 2개만으로도 실용 도구는 완성된다. 12개 표면 전부를 쓰는 건 과한가? + +**결정**: 모든 표면 사용. 단, 각 표면을 "쓰기 위해 쓰는" 게 아니라 **특정 마찰을 제거하는 역할로만 배치**. Keybindings는 가장 가치가 낮다는 것을 명시 (README 표에서 "가장 낮은 가치" 레이블). 정당화되지 않는 표면은 쓰지 않는 편이 낫다는 기준을 세움. + +**왜**: 포트폴리오 가치(레퍼런스 구현체) + 학습 가치(각 표면의 실제 제약을 체감) + 코드 재사용 설계(MCP를 공유하면 표면 추가가 오히려 쉬워짐). + +### 3.2 Plugin과 Standalone CLI의 중복 문제 + +둘 다 지원하면 slash command 본문과 CLI prompt 본문이 이중화된다. 유지보수 악몽. + +**결정**: `.claude/commands/*.md`를 단일 소스로 두고, CLI가 파일 시스템에서 직접 markdown body를 로드해 `ClaudeAgentOptions`로 넘김. → skill 1회 작성으로 slash + subcommand 동시 지원. `test_no_orphan_subcommands`가 불일치를 막음. + +**영향**: Phase 7에서 `doctor`를 추가할 때 CLI 전용(slash 커맨드 없음)이라는 예외가 생겼고, `cli_only_allowlist = {"version", "doctor"}`로 명시적 화이트리스트 처리. + +### 3.3 Windows cp949 locale 지원 + +`doctor` 구현 중 `subprocess.run(text=True)`가 cp949 locale에서 `UnicodeDecodeError` 발생. macOS/Linux CI에서는 안 보이는 문제. + +**결정**: 모든 subprocess 호출에 `encoding="utf-8", errors="replace"` 명시. Hook 스크립트에는 별도 메모리에 "Windows 환경 제약" 저장해 반복 학습 회피. + +### 3.4 CI가 3개 커밋 동안 Red였지만 알아채지 못함 + +`phase-9` 머지 후 `test_referenced_hook_scripts_exist`가 Linux/macOS에서 실패하고 있었으나, 로컬 Windows에서는 pathlib가 backslash를 흡수해 통과. 알림 파이프라인 부재로 3 커밋 동안 모르고 진행. `doctor` PR에서야 발견. + +**결정**: +1. 즉시 수정: 정규식 `[^\"]+` → `[^\"\\]+` (trailing backslash 제외) +2. 같은 PR에 pre-existing lint 에러(24건) 일괄 정리 — 한 번의 green bar 복원 +3. 메모리에 "CI 알림 파이프라인 필요" 기록 → 다음 v0.1.x 후보로 큐잉 + +**배운 점**: 멀티 OS 매트릭스만 있으면 안 되고, **실패를 알려주는 채널**이 필요. (다음 반복에서 Slack webhook or badge monitoring 예정) + +### 3.5 자신의 PreToolUse Hook에 막힘 (self-dogfooding) + +PR #3 머지 시 `gh pr merge`를 시도했으나 내가 Phase 3에서 만든 PreToolUse guard가 `gh pr merge is denied. Merge through the GitHub UI after maintainer review.`로 차단. + +**결정**: 우회하지 않음. 사용자가 GitHub UI로 직접 머지. → **이 프로젝트의 보안 정책이 실제로 작동한다는 증거**. CHANGELOG와 포트폴리오에 이 일화를 남김. + +### 3.6 `ossmate doctor` 스코프 (평가 후 선택) + +Phase 9 회고에서 "온보딩 마찰"이 중간 심각도 약점으로 식별. 후보 3개: + +| 후보 | 범위 | 리스크 | +|---|---|---| +| Eval suite | 크다 (2~3일) | 스코프 터짐 | +| Hygiene bundle (템플릿 등) | 작다 (30분) | 임팩트 약함 | +| **`ossmate doctor`** (선택) | 중간 (2~3시간) | 적절 | + +**결정 근거**: 가장 흔한 실패 케이스(gh 미설치, 디렉터리 오류, MCP 불량)의 80%를 1개 명령으로 자가 진단. 신규 의존성 0개 (기존 `rich` 재사용). 6개 check × ≥5개 테스트로 스코프 고정. → PR #3으로 merge. + +### 3.7 Dead link 청소 (PR #4) + +`docs/architecture.md` 링크가 README에 있었으나 파일이 존재하지 않음(사용자가 발견). 그 외 2개 phase 문서 링크도 메모리 경로(`memory/project_phases.md`)로 잘못 연결. + +**결정**: 파일을 새로 만드는 대신 표를 인라인화(README 12-surface 정당화). phase 설명만 실제 공개 문서 가치가 있으므로 `docs/project_phases.md`로 materialize. 부수적으로 `.claude/CLAUDE.md`의 "docs는 공개 explainer만 허용" 규칙을 완화해 docs/ 사용 경로를 열어둠. + +**배운 점**: 공개 저장소의 dead link는 recruiter 신뢰도에 직접적 영향 → 작은 docs 청소가 기술 구현만큼 중요. + +--- + +## 4. 자체 평가 + +### 잘한 점 + +- **스코프 통제**: 10 phase 계획 → 실제로 10 phase에서 v0.1.0 cut. 중간에 추가 ambition 없이 릴리스. `[Unreleased]` 규약으로 v0.1.x 반복 빌드. +- **self-dogfooding**: 자기 repo에서 Ossmate가 돌아감. 훅이 나를 막고, scheduled trigger가 이 저장소에 daily digest를 돌리고, CHANGELOG는 Ossmate가 생성. 메타적 일관성. +- **테스트 밀도**: 176 hermetic 테스트, ~5s. 신규 기능마다 ≥5개 추가 규칙. pre-existing 버그까지 같은 PR에서 치워 CI가 항상 green. +- **멀티 플랫폼**: Windows에서 개발, Linux/macOS CI에서 검증. cp949 · path separator · hook 실행 규약 모두 명시적으로 해결. +- **OIDC 배포**: PyPI 토큰 시크릿 0개. 태그 push로 릴리스, 워크플로우가 tag vs pyproject 버전 불일치를 거부. +- **Dogfood 설계 결정이 증명됨**: PreToolUse hook이 내 자신의 `gh pr merge`를 실제로 막았다는 경험 — 보안 정책이 살아있음을 확인. + +### 약한 점 + +- **CI 알림 갭**: 3 커밋 동안 main이 red였으나 알아채지 못함. Badge/Slack/email 파이프라인 없음. 다음 반복의 최우선 후보. +- **온보딩 마찰**: `doctor`로 80% 완화했으나, 여전히 `pipx` + `gh auth` + MCP 설치까지 수 단계. 신규 사용자에게는 많다. +- **실제 사용자 0명** (나 제외): Phase 9까지는 빌드 사이클, v0.1.x 이후에야 공개. 현재로선 adoption 데이터가 없어 실제 가치 측정 한계. +- **Keybindings 표면**: 12 표면 중 가장 약한 고리. 솔직하게 "가장 낮은 가치"로 레이블링했지만, 포함 여부를 다시 고민할 만함. +- **Node.js 20 deprecation** 등 actions 버전 관리: dependabot 미설정 상태로 메인테이너 주기가 오면 수동 감시 필요. + +### 이 프로젝트에서 배운 것 + +1. **도구를 만드는 것보다 "어떤 마찰을 없애는지" 명확히 하는 게 먼저**. 12개 표면 각각을 친숙해지기 위해 쓰는 게 아니라, 특정 마찰의 해소자로만 배치한 것이 전체 응집도를 결정함. +2. **공통 데이터 소스(MCP)에 투자**. Plugin과 CLI를 둘 다 지원한 대신 +3. **자기 도구로 자기를 관리하면(self-dogfood) 버그가 자발적으로 드러남**. Hook이 나를 막을 때, 정책이 설계대로 작동하는지 확인할 수 있었음. +4. **"독립 시연 가능한 phase"**라는 스코프 원칙이 기술/인지 부채를 막는다. +5. **Windows 개발 + Linux CI**는 공짜가 아니다. 로컬에서 안 보이는 실패를 잡으려면 매트릭스와 알림 파이프라인을 같이 갖춰야 함 (후자는 아직 미흡). +6. **구현하려는 것에 대한 이해가 중요** 하네스 프로그래밍을 위해 클로드 코드가 추천한 OSS support 프로젝트를 수행했는데 OSS 관리에 대한 배경지식이 부족하다보니까 개발이 어려웠다. 외주를 진행했다는 느낌으로 프로젝트를 수행했다. 다음에 프로젝트를 한다면 개발하려는 분야의 도메인 지식을 먼저 쌓고 개발 시작할 것 + + +### 다음 v0.1.x 로드맵 후보 + +- CI 실패 알림 파이프라인 (Slack webhook / email / badge audit) +- Dependabot + Node.js 20 → 최신 actions 버전 상향 +- PR/Issue 템플릿 (`.github/` 아래) +- 실제 사용자 피드백 수집 후 `doctor` 체크 확장 (git-lfs, Node 버전, 플러그인 마켓 동기화) +- Eval suite — skill 출력 품질 회귀 감지 + +--- + +## 관련 문서 + +- [README](../README.md) — 빠른 시작, 표면별 가치 +- [docs/project_phases.md](project_phases.md) — 10개 phase 상세 계획 +- [CHANGELOG](../CHANGELOG.md) — 버전별 변경 이력 (Ossmate 자체가 생성) +- [CONTRIBUTING](../CONTRIBUTING.md) — 개발 환경 / 커밋 규약