@natjswenson/devlog 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,61 @@
2
2
 
3
3
  All notable changes to `@natjswenson/devlog` are documented here.
4
4
 
5
+ ## 0.14.0 (2026-09-09) — verified concept guides and AI cover composition
6
+
7
+ - Add an explicit concept-guide draft workflow: select one transferable reader
8
+ outcome, include a copyable implementation prompt and complete reference, exercise
9
+ the build, and independently test adaptation in an existing project.
10
+ - Add `lint-guide` and `prepare-guide` for strict handoff structure and a standalone
11
+ local reading preview with exact full-guide clipboard and manual fallback.
12
+ - Add `compose-art-cover` for offline composition of local raster artwork with
13
+ adopted brand tokens, true-color PNG output, bounded typography and hashed receipts.
14
+ Codex native image generation remains session orchestration; no new credentials,
15
+ image API calls or paid fallback are introduced in the CLI.
16
+ - Package the workflow references for both hosts and install them beside standalone
17
+ SKILL.md copies. Existing Claude generation uses its local cover renderer.
18
+ - Update Sharp from 0.35.3 to 0.35.4 to resolve the dependency audit's
19
+ [libheif advisory](https://github.com/advisories/GHSA-rgj7-g3m4-5g8c).
20
+ - Add optional `generationMode: concept` for at most one complete guide per normal
21
+ run, with `release` and missing settings preserving existing generation behavior.
22
+ - Add `publish-guide` to bind the article, full agent payload, executed output,
23
+ independent adaptation and review records before writing a new entry. Reviewed
24
+ cover hashes and decoded geometry are checked when art is provided.
25
+ - Keep legacy scanning, assembly, rendering, publication identities and existing
26
+ content unchanged. Explicit drafts remain local; catalog backfill is separate.
27
+
28
+ ## 0.13.0 (2026-07-29) — a publish run now proves the entry is live
29
+
30
+ Publishing reported success on a post that was never reachable. The content, cover
31
+ and manifest all landed correctly, the push succeeded, every command returned `ok`,
32
+ and the entry 404'd for an hour because the site's own project registry had never
33
+ been told the project existed. A push is not a route, and this release stops the
34
+ skill treating the two as the same thing.
35
+
36
+ - **Added: `publish-entry` returns `firstEntryForProject`.** True when the call
37
+ created a project's first live entry, which is exactly when a rendering site needs
38
+ a new registry row. A project holding only tombstones still counts as first, since
39
+ a retired entry never implied a route. Previously nothing distinguished a project's
40
+ first publish from its fiftieth, so the one moment registration is required looked
41
+ identical to every run where it isn't.
42
+ - **Added: `siteUrl` config field** (settable, optional, trailing slash stripped,
43
+ http(s) only) plus `siteUrl` in the scan output. The repo name is not the site name
44
+ — a repo named `example.io` is commonly served at `example.com` — so a publish run
45
+ had no way to reach the page it had just published.
46
+ - **Added: SKILL.md Generate step 5b (register a project the site has never
47
+ rendered).** Find the site's registry, add the project, and *build the clone to
48
+ confirm the route exists* before pushing. Also warns that registry position can
49
+ decide feed order: a site sorting by date alone falls back to load order for
50
+ same-date entries, so a project appended last can render its newest entry last.
51
+ - **Added: SKILL.md Generate step 6 (verify the entry is live).** Poll the published
52
+ URL until it returns 200 before reporting success; on a persistent 404, check the
53
+ registry first, then the host's build log, and report it as **not live**. With no
54
+ `siteUrl` configured, the run must say the entry is pushed but unverified rather
55
+ than call it published.
56
+ - **Changed: the confirmation block leads with the verified live URL**, with the repo
57
+ blob URL demoted to secondary, and prints the failure on the `Live:` line rather
58
+ than a URL that may 404.
59
+
5
60
  ## 0.12.0 (2026-07-28) — five composition slots; stop defaulting to before/after
6
61
 
7
62
  Minor rather than patch: this adds three new named composition slots, so covers
package/README.md CHANGED
@@ -1,71 +1,171 @@
1
1
  # devlog
2
2
 
3
- [![npm](https://img.shields.io/npm/v/@natjswenson/devlog?color=blue)](https://www.npmjs.com/package/@natjswenson/devlog)
4
- [![license](https://img.shields.io/npm/l/@natjswenson/devlog)](./LICENSE)
5
- [![security](https://img.shields.io/badge/security-audited-green)](./SECURITY.md)
6
- [![vulnerabilities](https://img.shields.io/badge/npm%20audit-0%20issues-brightgreen)](#security)
3
+ <!-- >>> press:masthead v0.9.0 sha256:4b48a8031589 GENERATED by @natjswenson/press, do not edit -->
4
+ **NS** · NATE SWENSON · CLAUDE CODE + CODEX SKILL · PRESS v0.9.0 · linkedin.com/in/natejswenson
7
5
 
8
- A Claude Code skill that turns each version release (a git tag) into a published how-to guide, written in your own voice — and a React example for displaying it on your site.
6
+ ---
7
+ <!-- <<< press:masthead -->
9
8
 
10
- > **Build in public, by release.** Tag a release like you always do. Run `/devlog`. Each new version shows up on your site as a polished, end-to-end implementation guide in your voice, with cited sources and the gotchas you actually hit — not raw commit messages.
9
+ *Turn each release into a published how-to guide, written in your own voice.*
11
10
 
12
- ## Live example
11
+ > **Never write a detail you did not read from the repository.** Every command, hash and quote in an entry is checked against git, because a plausible one is a fabricated one.
13
12
 
14
- The skill is in production at [natejswenson.com/devlog](https://natejswenson.com/devlog), publishing to [github.com/natejswenson/daily-dev-log](https://github.com/natejswenson/daily-dev-log). What you see on that page is exactly what `npx @natjswenson/devlog preview` renders for you locally.
13
+ [![npm](https://img.shields.io/npm/v/@natjswenson/devlog?color=blue)](https://www.npmjs.com/package/@natjswenson/devlog) [![license](https://img.shields.io/npm/l/@natjswenson/devlog)](./LICENSE) [![security](https://img.shields.io/badge/security-audited-green)](./SECURITY.md)
15
14
 
16
- ## How it works
15
+ ## Why install this
16
+
17
+ "Build in public" usually means either nothing, or a changelog nobody reads.
17
18
 
18
- 1. **You ship a release** tag it (e.g. `git tag v0.3.0`), like you already do.
19
- 2. **Run `/devlog` in Claude Code.** The skill runs `devlog scan` to find tags that don't yet have an entry, researches the engineering topic behind each release, and writes a full setup → build → use → verify how-to guide (with a required `## Gotchas` section mined from your real fix commits, and 3+ cited sources). Every draft passes a deterministic lint (`devlog lint-post`) plus a quality self-review before it publishes. It's idempotent re-running does nothing until you cut a new release, and a published entry is never overwritten (`devlog publish-entry` refuses).
20
- 3. **Your site fetches it.** Static `manifest.json` + per-release markdown files served from `raw.githubusercontent.com` no backend needed.
19
+ Tag a release like you always do. Run `/devlog`. Each new version shows up on
20
+ your site as a polished, end-to-end implementation guidein your voice, with
21
+ cited sources and the gotchas you actually hit not raw commit messages.
21
22
 
22
- You can also manage configuration conversationally in Claude Code: "add this repo to devlog", "stop tracking X", "set min sources to 4", or `/devlog status` to see what would be generated without writing anything.
23
+ Each post is a **detailed how-to**: a reader who has never seen your repo can
24
+ follow it. Every draft passes a deterministic lint plus a quality self-review
25
+ before it publishes, and a published entry is never overwritten.
23
26
 
24
- **In your voice.** Entries are written using a voice profile, resolved in this order: your `config.voicePath` → [ghostwriter](../ghostwriter)'s `voice/` dir if installed → a bundled default. devlog reads `voice-profile.md` (and `voice-notes.md` overrides) — never ghostwriter's `algorithm.md`, since LinkedIn reach tuning doesn't apply to a dev log.
27
+ It is in production at [natejswenson.com/devlog](https://natejswenson.com/devlog),
28
+ publishing to
29
+ [github.com/natejswenson/daily-dev-log](https://github.com/natejswenson/daily-dev-log).
30
+ What you see on that page is exactly what `devlog preview` renders locally.
31
+
32
+ ## What you get
33
+
34
+ | Path | What it provides |
35
+ |---|---|
36
+ | `skills/devlog/SKILL.md` | The how-to contract every entry must satisfy. |
37
+ | `skills/devlog/bin/` | The CLI: `init`, `scan`, `lint-post`, `publish-entry`, `preview`, `config`. |
38
+ | `skills/devlog/lib/` | The deterministic core: scanning, linting, publishing, config validation. |
39
+ | `skills/devlog/examples/react/` | A drop-in React page for your own site. |
40
+ | `skills/devlog/preview/` | A complete deployable Vite app, if you have no site yet. |
41
+ | `skills/devlog/image-style/` | The PRESS cover-image palette and style guide. |
42
+ | [`SECURITY.md`](skills/devlog/SECURITY.md) | The full threat model and audit history. |
25
43
 
26
44
  ## Quick start
27
45
 
28
- ```sh
29
- npx @natjswenson/devlog init
46
+ Claude Code — run in chat:
47
+
48
+ ```text
49
+ /plugin marketplace add natejswenson/claude-skills
50
+ /plugin install devlog@claude-skills
51
+ /devlog
30
52
  ```
31
53
 
32
- That command:
33
- - Creates `<your-username>/daily-dev-log` on GitHub (or uses an existing one)
34
- - Installs the skill at `~/.claude/skills/devlog/`
35
- - Writes `~/.claude/skills/devlog/config.json` with your answers
36
- - Lets you register one or more projects in a single run
54
+ Codex — run in a terminal from the root of this repository checkout:
37
55
 
38
- Then:
56
+ ```bash
57
+ codex plugin marketplace add "$PWD"
58
+ codex plugin add devlog@claude-skills
59
+ ```
60
+
61
+ Start a new Codex session, then invoke in chat:
62
+
63
+ ```text
64
+ $devlog
65
+ ```
39
66
 
40
67
  ```sh
41
- npx @natjswenson/devlog preview
68
+ npx @natjswenson/devlog init # create the repo, install the skill, write config
69
+ npx @natjswenson/devlog preview # see it rendered at http://localhost:5173
42
70
  ```
43
71
 
44
- to see your dev log rendered locally at `http://localhost:5173`.
72
+ `init` creates `<your-username>/daily-dev-log` on GitHub (or uses an existing
73
+ repo), installs the skill at `~/.claude/skills/devlog/`, writes its config, and
74
+ lets you register one or more projects in a single run.
75
+
76
+ > **Run from any directory *outside* a clone of this repo.** Running inside it
77
+ > causes a `package.json` name collision and `npx` fails with
78
+ > `command not found`.
79
+
80
+ ## Triggers
81
+
82
+ - "/devlog", or "write a devlog entry".
83
+ - A release you just tagged that should become a post.
84
+ - Managing devlog config conversationally: "add this repo to devlog", "stop
85
+ tracking X", "set min sources to 4", "/devlog status".
86
+ - "Draft one concept guide using the agent-friendly method" or "consolidate these
87
+ posts into one guide" selects the new local draft workflow.
88
+ - "Create an AI cover draft for this article" selects the Codex artwork workflow
89
+ without scanning or publishing.
90
+
91
+ ## Requirements
45
92
 
46
- ## Prerequisites
93
+ - **Claude Code:** Authenticate `gh` in the shell and allow web research for release guides.
94
+ - **Codex:** Use the same authenticated `gh` CLI and available web tools. `init` still writes its legacy Claude skill copy; the Codex plugin is installed separately above.
95
+ - **Personal data:** Both hosts retain config, voice fallback and image-style assets in `~/.claude/skills/devlog/`; an existing `~/.claude/ghostwriter/voice` can also supply the voice.
47
96
 
48
- - **Node 18+** for the CLI and preview app
49
- - **GitHub CLI** (`gh`), authenticated with `gh auth login` — used to create your dev-log repo and push entries
50
- - **Claude Code** to run the `/devlog` skill
97
+ See [Codex migration notes](../../docs/codex-migration.md) for host tools and retained data paths.
98
+
99
+ - **Node 18+** for the CLI and preview app.
100
+ - **GitHub CLI** (`gh`), authenticated with `gh auth login` — used to create your
101
+ dev-log repo and push entries.
102
+ - **Claude Code** (`/devlog`) or **Codex** (`$devlog`) to run the skill.
103
+ - Concept drafts use independent agents for review/adaptation when available;
104
+ missing capabilities retain the draft with explicit uncompleted checks.
105
+ - AI artwork requires the session's native image tool. No implicit API fallback.
106
+
107
+ ## How it works
108
+
109
+ 1. **You ship a release** — tag it, like you already do.
110
+ 2. **Run `/devlog` in Claude Code.** The skill runs `devlog scan` to find tags
111
+ with no entry, researches the engineering topic behind each release, and
112
+ writes a full setup → build → use → verify guide, with a required
113
+ `## Gotchas` section mined from your real fix commits and 3+ cited sources.
114
+ It is idempotent: re-running does nothing until you cut a new release.
115
+ 3. **Your site fetches it.** Static `manifest.json` plus per-release markdown
116
+ served from `raw.githubusercontent.com`. No backend needed.
117
+
118
+ **In your voice.** Entries use a voice profile resolved in this order: your
119
+ `config.voicePath` → [ghostwriter](../ghostwriter)'s `voice/` dir if installed →
120
+ a bundled default. devlog reads `voice-profile.md` and `voice-notes.md`
121
+ overrides, never ghostwriter's `algorithm.md`, since LinkedIn reach tuning does
122
+ not apply to a dev log.
51
123
 
52
124
  ## Commands
53
125
 
54
126
  | Command | What it does |
55
127
  |---|---|
56
- | `npx @natjswenson/devlog init` | One-time setup: create dev-log repo, install skill, write config |
57
- | `npx @natjswenson/devlog add-project` | Register a project (interactive; `--yes --path <p>` for non-interactive/agent use) |
58
- | `npx @natjswenson/devlog remove-project <key> --yes` | Unregister a project (published entries stay) |
59
- | `npx @natjswenson/devlog set <field> <value>` | Update one config field (`targetRepo`, `branch`, `gitAuthor`, `githubUser`, `voicePath`, `deepDive.minSources`, `deepDive.topicDomains`) |
60
- | `npx @natjswenson/devlog config [--json]` | Show your current config with validation status |
61
- | `npx @natjswenson/devlog scan [--project <key>]` | JSON plan of new releases needing entries (used by the skill) |
62
- | `npx @natjswenson/devlog lint-post <file>` | Deterministic post-contract check (used by the skill) |
63
- | `npx @natjswenson/devlog publish-entry ...` | Copy a drafted entry into a clone + update the manifest; never overwrites (used by the skill) |
64
- | `npx @natjswenson/devlog preview` | Run a local preview at `http://localhost:5173` |
65
- | `npx @natjswenson/devlog --help` | Usage |
66
- | `npx @natjswenson/devlog --version` | Version |
67
-
68
- > **Tip:** run from any directory *outside* a clone of this repo. Running inside the repo causes a `package.json` name collision and `npx` fails with `command not found`.
128
+ | `devlog init` | One-time setup: create dev-log repo, install skill, write config |
129
+ | `devlog add-project` | Register a project (interactive; `--yes --path <p>` for agent use) |
130
+ | `devlog remove-project <key> --yes` | Unregister a project (published entries stay) |
131
+ | `devlog set <field> <value>` | Update one config field |
132
+ | `devlog config [--json]` | Show current config with validation status |
133
+ | `devlog scan [--project <key>]` | JSON plan of new releases needing entries |
134
+ | `devlog lint-post <file>` | Deterministic post-contract check |
135
+ | `devlog lint-guide <file> [--voice]` | Post checks plus a unique top-of-post implementation handoff |
136
+ | `devlog prepare-guide --article <md> --brand <json> --out <new-dir> [--cover <png>]` | Standalone local preview and complete copyable prompt/reference |
137
+ | `devlog compose-art-cover --spec <json> --out <new-dir>` | Offline raster artwork composition and hashed result; no image-service call |
138
+ | `devlog publish-entry ...` | Copy a drafted entry into a clone and update the manifest; never overwrites |
139
+ | `devlog preview` | Run a local preview at `http://localhost:5173` |
140
+
141
+ ## Concept guides and cover drafts
142
+
143
+ Explicit concept requests produce at most one complete guide teaching implementation
144
+ in the reader's project. The draft includes the full code, verification commands and
145
+ a prompt that preserves the reader's APIs, saved state and supported runtimes. The
146
+ preview's **Copy prompt + guide** button includes the full Markdown reference; denied
147
+ clipboard access provides a manual selection fallback.
148
+
149
+ The [concept workflow](skills/devlog/references/concept-guides.md) separates mechanical
150
+ lint from executed examples and independent adaptation evidence. The
151
+ [art workflow](skills/devlog/references/codex-cover-art.md) uses native Codex generation
152
+ followed by local typography. [Composition specs](skills/devlog/references/cover-spec.md)
153
+ consume generated/adopted brand JSON and local artwork; no installed PRESS dependency
154
+ is required. Sources remain intact, output directories must be new, and result markers
155
+ are written last. Review hashes identify artifacts, not proof of beautiful or correct art.
156
+
157
+ Default `/devlog` and `$devlog` retain release generation. Opt in with
158
+ `devlog set generationMode concept` to produce at most one complete concept guide
159
+ per normal run, including executed examples, an independent adaptation trial,
160
+ reviewed art and deployment verification. `devlog set generationMode release`
161
+ restores the legacy workflow. Explicit draft requests remain local.
162
+
163
+ The [publishing workflow](skills/devlog/references/guide-publishing.md) uses
164
+ `publish-guide --clone <content-root> --article <md> --evidence <json> [--cover <png>]`
165
+ to validate matching evidence before writing an unoccupied release identity.
166
+ It never pushes by itself. Installation does not change user configuration,
167
+ rewrite old posts or add a suppression ledger. Existing-post consolidation and
168
+ backfill remain separate explicitly scoped work.
69
169
 
70
170
  ## What you end up with
71
171
 
@@ -86,21 +186,9 @@ github.com/<you>/daily-dev-log/ # Created by init, populated by /devlog
86
186
  └── ...
87
187
  ```
88
188
 
89
- ## Manual setup (if you prefer)
90
-
91
- ```sh
92
- gh repo create <you>/daily-dev-log --public --add-readme
93
- mkdir -p ~/.claude/skills/devlog/voice
94
- curl -o ~/.claude/skills/devlog/SKILL.md https://raw.githubusercontent.com/natejswenson/devlog/main/SKILL.md
95
- # Optional fallback voice profile (used when voicePath and ghostwriter are both absent):
96
- curl -o ~/.claude/skills/devlog/voice/voice-profile.md https://raw.githubusercontent.com/natejswenson/devlog/main/voice/voice-profile.example.md
97
- curl -o ~/.claude/skills/devlog/voice/voice-notes.md https://raw.githubusercontent.com/natejswenson/devlog/main/voice/voice-notes.example.md
98
- # Then copy config.example.json → ~/.claude/skills/devlog/config.json and fill it in
99
- ```
100
-
101
189
  ## Add to your site
102
190
 
103
- ### React (drop-in)
191
+ **React (drop-in):**
104
192
 
105
193
  ```sh
106
194
  cp -r examples/react/ your-site/src/devlog/
@@ -114,30 +202,30 @@ import DevLogPage from './devlog/DevLogPage.jsx';
114
202
  <DevLogPage project="myproject" />
115
203
  ```
116
204
 
117
- Full instructions: [`examples/react/README.md`](./examples/react/README.md).
205
+ Full instructions: [`examples/react/README.md`](skills/devlog/examples/react/README.md).
118
206
 
119
- ### No site yet?
207
+ **No site yet?** The `preview/` directory is a complete deployable Vite app. Set
208
+ `VITE_DEVLOG_OWNER` / `VITE_DEVLOG_REPO` / `VITE_DEVLOG_PROJECTS` on Vercel,
209
+ Netlify or Cloudflare Pages, build with `vite build`, deploy `dist/`.
120
210
 
121
- The `preview/` directory is a complete deployable Vite app. Set `VITE_DEVLOG_OWNER` / `VITE_DEVLOG_REPO` / `VITE_DEVLOG_PROJECTS` env vars on Vercel, Netlify, or Cloudflare Pages, build with `vite build`, deploy `dist/`. See [`preview/README.md`](./preview/README.md).
122
-
123
- ### Other stacks (Next, Astro, plain HTML)
124
-
125
- It's static JSON and Markdown on GitHub. Build whatever UI you want — see the **Data contract** below.
211
+ **Other stacks (Next, Astro, plain HTML):** it is static JSON and Markdown on
212
+ GitHub. Build whatever UI you want against the data contract below.
126
213
 
127
214
  ## Data contract
128
215
 
129
- The dev-log repo has this layout, all served as raw files from `https://raw.githubusercontent.com/<owner>/<repo>/<branch>/`:
216
+ The dev-log repo has this layout, all served as raw files from
217
+ `https://raw.githubusercontent.com/<owner>/<repo>/<branch>/`:
130
218
 
131
219
  ```
132
220
  <repo>/
133
221
  └── <project-key>/
134
222
  ├── manifest.json # Index of all entries (newest first)
135
223
  ├── v0.3.0.md # One entry per release (named by version)
136
- ├── v0.2.0.md
137
224
  └── ...
138
225
  ```
139
226
 
140
- **`manifest.json`:**
227
+ `manifest.json`:
228
+
141
229
  ```json
142
230
  {
143
231
  "entries": [
@@ -146,13 +234,15 @@ The dev-log repo has this layout, all served as raw files from `https://raw.gith
146
234
  }
147
235
  ```
148
236
 
149
- Strict validation rules (entries that don't match are silently dropped by the React example):
237
+ Strict validation rules entries that do not match are silently dropped by the
238
+ React example:
239
+
150
240
  - `date` matches `YYYY-MM-DD` (the release/tag date)
151
241
  - `file` matches `^[a-zA-Z0-9._-]+\.md$`
152
242
  - `title` and `summary` are non-empty strings
153
243
  - `version` (optional) matches `^[a-zA-Z0-9._-]+$`
154
244
 
155
- **Entry markdown:**
245
+ Entry markdown:
156
246
 
157
247
  ```markdown
158
248
  ---
@@ -181,7 +271,8 @@ Real traps from the release's history, each: trap → symptom → escape.
181
271
  - commit message ([abc1234](https://github.com/.../commit/abc1234567...))
182
272
  ```
183
273
 
184
- That's the entire contract — `npx @natjswenson/devlog lint-post <file>` checks the mechanical parts of it.
274
+ That is the entire contract — `devlog lint-post <file>` checks the mechanical
275
+ parts of it.
185
276
 
186
277
  ## Configuration reference
187
278
 
@@ -189,84 +280,103 @@ That's the entire contract — `npx @natjswenson/devlog lint-post <file>` checks
189
280
 
190
281
  | Field | Type | Description |
191
282
  |---|---|---|
192
- | `targetRepo` | `"<owner>/<repo>"` | Repo where dev log entries are published. Must match `^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$`. |
283
+ | `targetRepo` | `"<owner>/<repo>"` | Repo where entries are published. Must match `^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*$`. |
193
284
  | `branch` | string (optional) | Branch in the dev-log repo. Defaults to `main`. Must not contain `..` or start with `-`. |
194
- | `gitAuthor` | string | Your name. Retained for backward compatibility; it is **not** currently rendered on entries (the author filter was removed, and release notes summarize all commits in a tag range). Still **required** by config validation — it must be present and non-empty (don't drop it). Whitespace OK; no shell metacharacters. |
285
+ | `gitAuthor` | string | Your name. Retained for backward compatibility; **not** currently rendered on entries, but still **required** by config validation. Whitespace OK; no shell metacharacters. |
195
286
  | `githubUser` | string | Your GitHub username. |
196
- | `voicePath` | string (optional) | Directory holding `voice-profile.md` (and optionally `voice-notes.md`) used to write entries in your voice. A leading `~` is expanded. If unset, devlog uses ghostwriter's `voice/` if installed, else the bundled default. Read only never shell-interpolated. |
287
+ | `voicePath` | string (optional) | Directory holding `voice-profile.md` (and optionally `voice-notes.md`). A leading `~` is expanded. Read only, never shell-interpolated. |
197
288
  | `projects` | array | One entry per project you want dev logs for. |
198
289
  | `projects[].key` | string | Subdirectory name in the dev-log repo. Strict token: `^[a-z0-9][a-z0-9._-]*$`, no `..`. |
199
290
  | `projects[].label` | string (optional) | Display name for the tab. Defaults to `key`. |
200
291
  | `projects[].path` | string | Local filesystem path to the project. Whitespace OK. |
201
- | `projects[].remote` | `"<owner>/<repo>"` | The project's GitHub remote. Used to mark public commits and link them. |
202
- | `projects[].pathFilter` | string (optional) | Repo-relative subdir scoping this project's commits in a monorepo (e.g. `skills/devlog`). |
203
- | `projects[].tagPrefix` | string (optional) | Prefix of the git tags that mark this project's releases (e.g. `devlog-v`). Defaults to `v`. Used in `git tag --list '<tagPrefix>*'`. |
204
- | `deepDive` | object (optional) | Controls the researched how-to. `topicDomains` (array, default `["AI", "DevOps/SRE", "software engineering"]`) steers topic selection; `minSources` (integer 1-10, default 3) is the floor of **distinct** cited source URLs per post. |
292
+ | `projects[].remote` | `"<owner>/<repo>"` | The project's GitHub remote, used to mark public commits and link them. |
293
+ | `projects[].pathFilter` | string (optional) | Repo-relative subdir scoping this project's commits in a monorepo. |
294
+ | `projects[].tagPrefix` | string (optional) | Prefix of the git tags marking this project's releases. Defaults to `v`. |
295
+ | `deepDive` | object (optional) | `topicDomains` steers topic selection; `minSources` (110, default 3) is the floor of **distinct** cited source URLs per post. |
296
+
297
+ See [`config.example.json`](skills/devlog/config.example.json) for a complete
298
+ template, or run `devlog config` to inspect yours with validation.
205
299
 
206
- See [`config.example.json`](./config.example.json) for a complete template, or run `npx @natjswenson/devlog config` to inspect your current config with validation.
300
+ ## Customization
301
+
302
+ - **Tweak the entry template:** edit `~/.claude/skills/devlog/SKILL.md` (Generate
303
+ mode, Step 3 — the how-to contract).
304
+ - **Tweak your voice:** edit `voice-profile.md` / `voice-notes.md` in your
305
+ `voicePath`.
306
+ - **Tune research depth:** `devlog set deepDive.minSources 4`, or
307
+ `set deepDive.topicDomains "security, platform engineering"`.
308
+ - **Tweak the UI:** override the `--devlog-*` CSS variables in
309
+ `examples/react/DevLogPage.css`.
310
+ - **Add or remove projects:** `devlog add-project` / `remove-project <key> --yes`,
311
+ or just tell Claude.
207
312
 
208
313
  ## Security
209
314
 
210
- The package is designed to be safe to install on a developer's machine and have ambient gh/git credentials. See [SECURITY.md](./SECURITY.md) for the full threat model and audit history.
315
+ The package is designed to be safe to install on a developer's machine holding
316
+ ambient `gh`/git credentials. See
317
+ [`SECURITY.md`](skills/devlog/SECURITY.md) for the full threat model.
318
+
319
+ - All shell calls in the CLI use `spawnSync` with argv arrays — no shell, no
320
+ injection surface.
321
+ - The skill validates every config field against an allowlist before
322
+ interpolating it into a shell command.
323
+ - Markdown rendering uses `react-markdown` with `skipHtml` and an allowlist
324
+ `urlTransform`; `data:`, `javascript:`, `vbscript:`, `file:` and `blob:` are all
325
+ neutralized.
326
+ - Frontmatter parsing uses `Object.create(null)` plus a key allowlist — no
327
+ prototype pollution.
328
+ - All external JSON is schema-validated before use.
329
+ - `config.json` is written atomically, mode 0600. All dependencies are pinned to
330
+ exact versions.
331
+
332
+ **To report a vulnerability:** open a
333
+ [GitHub security advisory](https://github.com/natejswenson/devlog/security/advisories/new).
334
+ Do not open a public issue.
211
335
 
212
- **At a glance:**
213
- - ✓ All shell calls in the CLI use `spawnSync` with argv arrays (no shell, no injection surface)
214
- - ✓ The skill validates every config field against an allowlist before interpolating into shell commands; instructs the LLM to single-quote interpolated values
215
- - ✓ Markdown rendering uses `react-markdown` with `skipHtml` and an allowlist `urlTransform` (only http(s)/mailto allowed; data:, javascript:, vbscript:, file:, blob: all neutralized)
216
- - ✓ Frontmatter parser uses `Object.create(null)` + key allowlist (no prototype pollution)
217
- - ✓ All external JSON is schema-validated before use (manifest, env-var projects array)
218
- - ✓ Vite dev server bound to `localhost`, CORS off
219
- - ✓ Demo-mode `window.fetch` override gated to dev builds only
220
- - ✓ `config.json` written atomically (tmp + rename), mode 0600
221
- - ✓ All dependencies pinned to exact versions
222
- - ✓ `npm audit`: 0 known vulnerabilities
336
+ ## Troubleshooting
223
337
 
224
- **To report a vulnerability:** open a [GitHub security advisory](https://github.com/natejswenson/devlog/security/advisories/new). Do not open a public issue.
338
+ **`sh: devlog: command not found` when running `npx`:** you are inside a checkout
339
+ of this repo. The local `package.json` name collides with the published one. Run
340
+ `npx` from somewhere else.
225
341
 
226
- ## Customization
342
+ **Preview is blank, no tabs, no entries:** check the browser console. CJS interop
343
+ errors on `react-dom/client`, `style-to-js` or `react-markdown` mean a pre-0.1.6
344
+ release — `npm cache clean --force && rm -rf ~/.npm/_npx && npx --yes @natjswenson/devlog@latest preview`.
345
+
346
+ **Init cannot find `gh`:** install it from [cli.github.com](https://cli.github.com/)
347
+ and run `gh auth login`.
227
348
 
228
- - **Tweak the entry template:** edit `~/.claude/skills/devlog/SKILL.md` (Generate mode, Step 3 — the how-to contract).
229
- - **Tweak your voice:** edit the `voice-profile.md` / `voice-notes.md` in your `voicePath` (or `~/.claude/skills/devlog/voice/`).
230
- - **Tune research depth:** `npx @natjswenson/devlog set deepDive.minSources 4`, or `set deepDive.topicDomains "security, platform engineering"`.
231
- - **Tweak the UI:** override the `--devlog-*` CSS variables in `examples/react/DevLogPage.css` to match your theme.
232
- - **Add or remove projects:** `npx @natjswenson/devlog add-project` / `remove-project <key> --yes` — or just tell Claude ("add this repo to devlog").
349
+ **`Config validation failed`:** run `devlog config` for a detailed diagnosis.
350
+ Common causes are shell metacharacters in a field, a project key containing `..`
351
+ or `/`, or a path that does not exist.
233
352
 
234
- ## Testing & evals
353
+ **Preview shows "Setup required":** you deployed the preview app standalone
354
+ without setting `VITE_DEVLOG_OWNER`, `VITE_DEVLOG_REPO` and
355
+ `VITE_DEVLOG_PROJECTS`.
235
356
 
236
- The deterministic core (`lib/`, the CLI) is covered by `npm test` (node:test; scan tests
237
- run against real throwaway git repos). The non-deterministic half — post quality — is
238
- covered by a cost-capped eval harness:
357
+ ## Development
239
358
 
240
359
  ```sh
360
+ cd skills/devlog/skills/devlog
361
+ npm test # deterministic core; scan tests use real throwaway git repos
241
362
  node evals/run_eval.mjs --mock # $0, runs in CI; deterministic layer only
242
363
  node evals/run_eval.mjs --live # LLM judge on golden fixtures; quotes spend, hard cap $0.50
243
364
  ```
244
365
 
245
- The judge scores reproducibility, code completeness, gotcha quality, citations, voice,
246
- and scope honesty (pass ≥ 7/10). Without `ANTHROPIC_API_KEY` in the environment, mock
247
- mode is forced CI can never spend money.
248
-
249
- ## Troubleshooting
250
-
251
- **`sh: devlog: command not found` when running `npx`:** you're inside a checkout of this repo. The local `package.json` name collides with the published one. Run `npx` from somewhere else, e.g. `cd ~ && npx @natjswenson/devlog ...`.
366
+ Node skill. The judge scores reproducibility, code completeness, gotcha quality,
367
+ citations, voice and scope honesty (pass ≥ 7/10). Without `ANTHROPIC_API_KEY` in
368
+ the environment, mock mode is forced, so **CI can never spend money**.
252
369
 
253
- **Init prompts show `78` after placeholder text:** that's an artifact of how some output capture tools render `\x1b7`/`\x1b8` (cursor save/restore) escape sequences. In a real interactive terminal, you won't see it.
370
+ The baseline is pinned against 8 entries actually published to natejswenson.io
371
+ a curated subset on purpose, since only 17 of 61 published entries satisfy
372
+ today's contract and asserting over all 61 would encode "the linter must accept
373
+ its own history".
254
374
 
255
- **Preview is blank / no tabs / no entries:** check the browser console. If you see CJS interop errors related to `react-dom/client`, `style-to-js`, or `react-markdown`, you're on a pre-0.1.6 release — upgrade with `npm cache clean --force && rm -rf ~/.npm/_npx && npx --yes @natjswenson/devlog@latest preview`.
256
-
257
- **Init can't find `gh`:** install via [cli.github.com](https://cli.github.com/) and run `gh auth login`.
258
-
259
- **`Config validation failed: ...`** — the validator rejected something in your `config.json`. Run `npx @natjswenson/devlog config` for a detailed diagnosis. Common causes:
260
- - A field has shell metacharacters (`;` `&` `|` `` ` `` `$` etc) — see SKILL.md for the full list
261
- - A project key contains `..` or `/`
262
- - A path doesn't exist on disk
263
-
264
- **Preview shows "Setup required":** you deployed the preview app standalone but didn't set the env vars. Set `VITE_DEVLOG_OWNER`, `VITE_DEVLOG_REPO`, `VITE_DEVLOG_PROJECTS` (JSON-stringified array) in your hosting environment.
265
-
266
- ## Versioning
375
+ ## Changelog
267
376
 
268
- Releases are documented in [CHANGELOG.md](./CHANGELOG.md). The package follows semver bug fixes/security patches in patch releases (0.1.x), behavior changes in minor (0.x.0).
377
+ See [`CHANGELOG.md`](CHANGELOG.md). Releases are cut by a version bump, tagged
378
+ `devlog-v<version>`, and published to npm.
269
379
 
270
380
  ## License
271
381
 
272
- MIT
382
+ MIT — see [`LICENSE`](LICENSE).