
Document Studio
Scaffold and validate structured product docs—ADRs, PRDs, specs, and kanban boards—with consistent YAML frontmatter in a solo builder repo.
Overview
Document Studio is an agent skill most often used in Build (also Validate scope, Operate iterate) that scaffolds ADR, PRD, spec, and kanban markdown with validated YAML frontmatter.
Install
npx skills add https://github.com/mols3131d/mols-agent-assets --skill document-studioWhat is this skill?
- Supports four DocType values: adr, prd, spec, and kanban
- Frontmatter model with parse_yaml_frontmatter and validate_frontmatter
- DocStatus lifecycle enums from draft through superseded and kanban states (backlog, in-progress, done)
- Utilities for kebab-case normalization, title-case names, and YAML list formatting
- write_if_not_exists to avoid clobbering human-edited files
- 4 DocType values: adr, prd, spec, kanban
- DocStatus covers draft through superseded plus kanban workflow states
Adoption & trust: 1 installs on skills.sh; trending (+100% hot-view momentum).
What problem does it solve?
Your agent keeps dumping plans into chat or inconsistent markdown files without shared types, statuses, or safe creation rules.
Who is it for?
Solo builders who want a small, typed document system inside the repo for specs and decision records before and during implementation.
Skip if: Teams that already standardize on Notion or Confluence only, or anyone who needs a full wiki CMS rather than agent-generated markdown templates.
When should I use this skill?
You need agents to create or update typed ADR, PRD, spec, or kanban markdown with validated frontmatter in the repository.
What do I get? / Deliverables
You get kebab-cased, frontmatter-valid document stubs aligned to ADR/PRD/spec/kanban models that agents can extend without overwriting existing files.
- Markdown files for adr, prd, spec, or kanban with YAML frontmatter
- Validated frontmatter payloads via validate_frontmatter
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Build → docs because the skill’s core output is typed markdown artifacts teams create while defining and tracking work. Docs subphase fits ADR/PRD/spec/kanban templates, frontmatter validation, and safe write-if-not-exists flows for agent-driven documentation.
Where it fits
Emit a draft PRD with proposed status and priority fields before you commit to a full build.
Spin up a kanban doc with backlog and in-progress columns encoded via DocStatus.
Record an ADR as accepted with normalized kebab-case filename and validated frontmatter.
Attach a spec doc in review status as the single source for launch checklist items.
Mark an ADR superseded and add a replacement stub using write_if_not_exists.
How it compares
Structured in-repo doc templates with validation—not a generic “write markdown” prompt or an external PM SaaS integration.
Common Questions / FAQ
Who is document-studio for?
Indie and solo developers who run AI coding agents and want ADRs, PRDs, specs, and kanban cards as first-class repo files with consistent metadata.
When should I use document-studio?
During Validate to draft a PRD or scope spec, in Build for ADRs and kanban task boards, and in Operate when you supersede ADRs or update doc status after shipping changes.
Is document-studio safe to install?
Treat it like any third-party agent asset: review the Security Audits panel on this Prism page and inspect the Python helpers before letting an agent write to your filesystem.
SKILL.md
READMESKILL.md - Document Studio
from core.enums import DocType, DocStatus, TaskPriority from core.utils import ( normalize_kebab_case, title_case_name, format_yaml_list, write_if_not_exists, unquote, parse_yaml_frontmatter, ) from core.models import Frontmatter, Document, validate_frontmatter __all__ = [ "DocType", "DocStatus", "TaskPriority", "normalize_kebab_case", "title_case_name", "format_yaml_list", "write_if_not_exists", "unquote", "parse_yaml_frontmatter", "Frontmatter", "Document", "validate_frontmatter", ] from enum import Enum class DocType(str, Enum): ADR = "adr" PRD = "prd" SPEC = "spec" KANBAN = "kanban" class DocStatus(str, Enum): DRAFT = "draft" PROPOSED = "proposed" ACCEPTED = "accepted" ACTIVE = "active" DEPRECATED = "deprecated" SUPERSEDED = "superseded" REJECTED = "rejected" IN_PROGRESS = "in-progress" REVIEW = "review" DONE = "done" BACKLOG = "backlog" TODO = "todo" APPROVED = "approved" class TaskPriority(str, Enum): LOW = "low" MEDIUM = "medium" HIGH = "high" from __future__ import annotations from pathlib import Path from typing import Any from core.utils import ( format_yaml_list, parse_yaml_frontmatter, ) class Frontmatter: """프론트매터 데이터를 캡슐화하고 다루는 모델 클래스.""" def __init__(self, data: dict[str, Any] | None = None) -> None: self._data = data or {} def get(self, key: str, default: Any = None) -> Any: return self._data.get(key, default) def set(self, key: str, value: Any) -> None: self._data[key] = value def delete(self, key: str) -> None: if key in self._data: del self._data[key] @property def id(self) -> str | None: return self.get("id") @property def title(self) -> str | None: return self.get("title") @property def status(self) -> str | None: return self.get("status") @property def priority(self) -> str | None: return self.get("priority") @property def assignee(self) -> str | None: return self.get("assignee") @property def description(self) -> str | None: return self.get("description") @property def tags(self) -> list[str]: val = self.get("tags") if isinstance(val, list): return val return [] def to_dict(self) -> dict[str, Any]: return dict(self._data) @classmethod def from_dict(cls, data: dict[str, Any]) -> Frontmatter: return cls(data) def serialize(self) -> str: """프론트매터 데이터를 YAML 형식 문자열로 시리얼라이즈한다.""" lines = [] for k, v in self._data.items(): if isinstance(v, list): lines.append(f"{k}: {format_yaml_list(v)}") elif isinstance(v, (int, float, bool)): lines.append(f"{k}: {str(v).lower() if isinstance(v, bool) else v}") elif v is None: lines.append(f"{k}: \"\"") else: val_str = str(v) if '"' in val_str: lines.append(f"{k}: '{val_str}'") else: lines.append(f"{k}: \"{val_str}\"") return "\n".join(lines) class Document: """마크다운 문서를 나타내는 도메인 모델 클래스.""" def __init__(self, path: Path | None = None, frontmatter: Frontmatter | None = None, body: str = "") -> None: self.path = path self.frontmatter = frontmatter or Frontmatter() self.body = body @classmethod def load(cls, path: Path) -> Document: """파일시스템에서 문서를 로드한다.""" content = path.read_text(encoding="utf-8") fm_data, body = parse_yaml_frontmatter(content) return cls(path=path, frontmatter=Frontmatter.from_dict(fm_data), body=body) def save(self, path: Path | None = None) -> None: """문서를 파일시스템에 저장한다.""" target_path = path or self.path if not target_path: