Claude
Skills
Sign in
Back

sync-spec

Included with Lifetime
$97 forever

Materialize a hard local copy of a Notion specification page tree as a flat `.code-spec/` bundle of `{kebab-title}-{32hex-id}.md` files (plus an auto-written `.gitignore`). Hard-gates on root spec persistence — the file whose 32-hex suffix matches the input id MUST exist non-empty. Use when downloading a Notion spec to disk, mirroring a Notion spec page tree locally, pulling a spec bundle for a ticket, refreshing a stale .code-spec bundle, or any time a guaranteed-on-disk copy of a Notion spec is needed before downstream analysis or codegen.

Productivity

What this skill does


# Sync Spec

## 1. INTRODUCTION

### Purpose & Context

**Purpose**: Download a Notion specification page tree to disk as a self-contained markdown bundle. Always wipes and re-downloads — this skill never caches, never merges, never preserves prior contents. Hard-gates on root `SPEC.md` persistence: if the root spec cannot be saved locally, the skill refuses with a structured reason and writes nothing else.

**When to use**:

- When the user asks to download or pull a Notion spec to disk
- When a ticket's `.code-spec/<slug>/` bundle is stale and needs a fresh copy
- When mirroring a Notion spec page tree locally before downstream codegen, audit, or review
- When any caller needs a guaranteed-on-disk hard copy of a Notion spec before proceeding
- When refreshing a local spec bundle to pick up Notion-side edits

**Prerequisites**:

- `notion-sync` CLI on PATH (verify with `Bash: notion-sync --help`)
- `NOTION_TOKEN` environment variable set in the current shell (export before invoking)
- Write access to the resolved `<spec-path>` directory
- A working directory inside (or under) a project (so `<spec-path>` defaults can resolve to a project root); otherwise falls back to `<CWD>/.code-spec`

### Your Role

You are a **Spec Bundle CLI Operator** who runs a single recursive `notion-sync pull` and validates the on-disk result. Your responsibilities are:

- **Path Discipline**: Resolve `<spec-path>` deterministically (project-root walk-up, then CWD fallback) and refuse to operate outside the project tree
- **Wipe Discipline**: Always wipe `<spec-path>` before the fetch — no caching, no merging, no preservation
- **One-Shot Recursion**: Issue exactly ONE `notion-sync pull <id> --follow --out <spec-path>` call. The CLI walks children + databases + links + files in a single invocation. Do NOT iterate per-page across tool turns.
- **Hard-Gate Authority**: After the pull, verify the file whose `{32hex-id}` filename suffix matches the input `notion_id` exists and is non-empty. Refuse the entire skill if not.
- **Faithful Reporting**: Emit a single YAML completion report describing every file persisted, with refusal reasons surfaced explicitly when applicable

## 2. SKILL OVERVIEW

### Skill Input/Output Specification

#### Required Inputs

- **`<notion-url-or-id>`**: Full Notion URL or bare 32-char hex id of the root spec page. Dashes are stripped during normalization.

#### Optional Inputs

- **`--spec-path=<dir>`**: Directory to write the bundle into. **Default**: walk up from CWD to the closest project root (first ancestor containing any of `.git/`, `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`) and use `<root>/.code-spec`. If no project root marker is found anywhere up to the filesystem root, fall back to `<CWD>/.code-spec`.

There are NO other arguments. There is **no** `--use-cache`, **no** `--repo`, **no** `--slug`, and **no** sync mode. The skill always wipes and re-downloads.

#### Expected Outputs

- **Bundle on disk** at `<spec-path>/` (flat, no subdirectories):
  - `{kebab-title}-{32hex-id}.md` for every page in the pulled subgraph (root + recursive children + linked leaves + database rows)
  - `.gitignore` — auto-written by `notion-sync`, single line `*`
- **Page identity** is the 32-hex suffix of the filename. The root page is the file whose suffix equals the input `notion_id`.
- **Completion Report (YAML)**: `status` (`completed` | `refused`), refusal `reason` if applicable, `outputs.notion`, `outputs.spec_bundle.spec_path`, `outputs.spec_bundle.files[]` (each entry `{ path, notion_id }`)

#### Data Flow Summary

The skill takes a Notion URL or id, normalizes it to a 32-char hex id, resolves an absolute `<spec-path>` (project-root walk-up with CWD fallback), safety-checks that the path is inside the resolved project root or under CWD, wipes the directory, runs ONE `notion-sync pull <id> --follow --out <spec-path>` call (which recursively writes flat `{kebab-title}-{32hex-id}.md` files for the entire subgraph plus a `.gitignore`), hard-gate verifies that the root file (filename suffix matches input `notion_id`) exists and is non-empty, and emits a YAML completion report. There is no caching, no merge, no second pass, and no per-page iteration across tool turns.

### Visual Overview

#### Main Skill Flow

```plaintext
   YOU
(CLI Operator — single linear flow)
   |
   v
[START]
   |
   v
[Step 1: Resolve & Normalize]
   |    • strip dashes, validate 32-char hex
   |    • walk up to project root for <spec-path>
   |    • refuse on invalid_id
   v
[Step 2: Wipe & Prepare]
   |    • safety check: path inside project root OR under CWD
   |    • Bash rm -rf <spec-path>
   |    • mkdir -p <spec-path>
   |    • ALWAYS wipes (no cache, ever)
   v
[Step 3: One-Shot Recursive Pull]
   |    • Bash: notion-sync pull <notion_id> --follow --out <spec-path>
   |    • SINGLE call walks children + databases + links + files
   |    • CLI auto-writes .gitignore at <spec-path>/.gitignore
   |    • files land flat: {kebab-title}-{32hex-id}.md
   |    • DO NOT iterate per-page across turns
   v
[Step 4: Enumerate]
   |    • Glob: <spec-path>/*.md → file list
   |    • parse 32-hex suffix from each filename → notion_id
   v
[Step 5: Hard-Gate Verification]  *** HARD GATE ***
   |    • locate file whose {32hex-id} suffix matches input notion_id
   |    • Bash test -s <root-file>
   |    • CLI exit ≠ 0 OR root file missing/empty → refuse
   |    • CLI exit 0 + root file present non-empty → completed
   v
[Step 6: Skill Completion Report]
   |    • emit YAML
   v
[END]

Legend:
═══════════════════════════════════════════════════════════════════
• Single operator — no subagent dispatch, no parallel fan-out
• ONE notion-sync pull does everything (recursion via --follow)
• Step 5 is the HARD GATE — no completed status without root file on disk
• Skill is LINEAR: 1 → 2 → 3 → 4 → 5 → 6
• On invalid_id (Step 1) or refusal at Step 5: jump straight to Step 6
═══════════════════════════════════════════════════════════════════

Note:
• Recursion happens INSIDE the CLI, not across tool turns
• No caching: every invocation is a fresh download
• No merging: pre-existing contents at <spec-path> are deleted
• No INDEX.md, no children/, no linked/ — bundle is flat
```

### Skill Steps

1. Resolve & Normalize (You) — strip dashes, validate 32-char hex, resolve `<spec-path>`
2. Wipe & Prepare (You) — safety check + `rm -rf` + `mkdir -p`
3. One-Shot Recursive Pull (You) — `notion-sync pull <id> --follow --out <spec-path>`
4. Enumerate (You) — `Glob: <spec-path>/*.md`, parse 32-hex suffix per filename
5. Hard-Gate Verification (You) — `test -s` on the file whose suffix matches input id
6. Skill Completion Report (You) — emit YAML

## 3. SKILL IMPLEMENTATION

### Step 1: Resolve & Normalize

**Step Configuration**:

- **Purpose**: Normalize the Notion id to 32-char hex and resolve an absolute `<spec-path>` deterministically. Refuse on malformed input before any disk mutation.
- **Input**: `<notion-url-or-id>`, optional `--spec-path=<dir>`
- **Output**: `notion_id` (32-char hex), `spec_path` (absolute), `project_root` (absolute or null)
- **Sub-skill**: None
- **Parallel Execution**: No

#### Actions (You)

1. **Receive inputs** from invocation; parse `<notion-url-or-id>`:
   - If a full URL, extract the trailing id segment
   - Strip all dashes
   - Validate the result is exactly 32 hex characters (`/^[0-9a-f]{32}$/i`)
   - **On validation failure**: set `status=refused`, `reason=invalid_id`, jump to Step 6. Do NOT wipe. Do NOT call `notion-sync`.
2. **Resolve `<spec-path>`**:
   - If `--spec-path=<dir>` provided: take it as-is, resolve to absolute path
   - Otherwise: walk up from CWD looking for the first ancestor containing any of `.git/`, `package.json`, `pyproject.toml`, `Cargo.toml`, `go.mod`
     - If found: `spec_path = <root>/.code-spec`
     - If no marker found anywhere up to filesystem root: `spec_path = <CWD>/.code-spec` (fallback)
   - Record `project_root` (the resolve

Related in Productivity