From 89231b63cdc1dc1a4f531b1b683a57cb0cfe0f03 Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Tue, 22 Sep 2026 17:07:15 -0400 Subject: [PATCH 1/3] chore: add committed commit-message skill under .agents/skills Mirrors webdriverio/driver's .agents/ convention (itself based on webdriverio/webdriverio's agent-infrastructure work), scaled to this repo's size: a thin AGENTS.md entry point, a concise-writing skill with this repo's own commit/PR/comment conventions, and a CLAUDE.md adapter that just points back to AGENTS.md instead of duplicating it. Existing Cursor Cloud instructions are preserved, folded into AGENTS.md's Setup section rather than replaced. Co-Authored-By: Claude Sonnet 5 --- .agents/README.md | 7 ++ .agents/skills/concise-writing/SKILL.md | 57 ++++++++++++++++ .gitignore | 3 + AGENTS.md | 90 ++++++++++++++++++++++--- CLAUDE.md | 4 ++ 5 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 .agents/README.md create mode 100644 .agents/skills/concise-writing/SKILL.md create mode 100644 CLAUDE.md diff --git a/.agents/README.md b/.agents/README.md new file mode 100644 index 0000000..67707c0 --- /dev/null +++ b/.agents/README.md @@ -0,0 +1,7 @@ +# Agent toolchain + +Canonical policy lives in [`/AGENTS.md`](../AGENTS.md). This directory only +holds: + +- [`skills/`](skills) — playbooks for coding agents. Read a skill's + `SKILL.md` only when its description matches the task at hand. diff --git a/.agents/skills/concise-writing/SKILL.md b/.agents/skills/concise-writing/SKILL.md new file mode 100644 index 0000000..4fd937a --- /dev/null +++ b/.agents/skills/concise-writing/SKILL.md @@ -0,0 +1,57 @@ +--- +name: concise-writing +description: Keep everything written in this repo — commit messages, PR titles/descriptions, and code comments — clear and terse. Use whenever creating a git commit, opening or updating a pull request, or writing/reviewing a code comment; also covers /commit and requests like "commit this", "open a PR", or "write a comment explaining this". +--- + +Everything written *about* the code in this repo — commit messages, PR descriptions, code comments — should say the minimum needed to be understood, and no more. The reader (a maintainer, a reviewer, a future agent) can already read the diff; don't narrate it back to them. Say what isn't obvious from the code itself: the *why*, not the *what*. + +This applies across three surfaces. Jump to the one you need: + +## Commit messages + +Gather context first — run together, since none depends on the others: +- `git status` — what's changed and what's untracked +- `git diff` (unstaged) and `git diff --staged` — the actual content +- `git log --oneline -15` — refresh on this repo's message style + +This repo's history is consistently `type: terse imperative summary`, e.g.: +``` +fix: isFloatRange misclassified symbolic range bounds as float +docs: explain the RFC 8610 BAD-range rationale in isFloatRange's JSDoc +ci: scope package releases to changed/modified packages, fix cross-package changelog bump +fix: generators emit wrong numeric type for floating-point ranges (#78) +``` +- One line, imperative mood, `type: summary`, no trailing period. +- Lead with *why*, not a mechanical restatement of the diff (bad: "update index.ts"; good: "isFloatRange misclassified symbolic range bounds as float"). +- Only add a body if the one-liner genuinely can't carry the reasoning — this repo's history mostly skips it, but a fix that isn't self-explanatory from the summary alone (e.g. it traces back to an RFC section, a specific bug repro, or a non-obvious root cause) earns one. Keep it to what a reader actually needs, not a walkthrough of the diff. +- Pick the type by what changed: `fix`, `feat`, `test`, `ci`, `docs`, `chore`, `build`, `refactor`. + +**Staging**: stage specific files by name (`git add path/to/file`), never a blanket `git add -A` or `git add .` — this repo's `.github/workflows/` files touch tokens and publish credentials, and a blind add risks scooping up something that doesn't belong. Check `git status` first for anything unexpected or secret-looking (`.env`, `credentials.json`, `*.pem`, `*token*`) and flag it instead of silently staging it. + +**Committing**: pass the message via a heredoc so formatting survives: +```bash +git commit -m "$(cat <<'EOF' +type: terse summary here +EOF +)" +``` +Append whatever attribution footer this session's own instructions specify — don't hardcode one here, since it can change independently of this skill. + +Never amend an existing commit unless explicitly asked — a fresh commit is the default, and never amend one that's already been pushed. Never pass `--no-verify` or otherwise skip hooks unless explicitly told to; if a pre-commit hook fails, fix the underlying issue and commit again. After committing, run `git status` to confirm it landed, and report back in one line what was committed — don't dump the full diff back at the user. + +## PR titles and descriptions + +- Title under ~70 characters, same "why, not what" rule as commit summaries, same `type: summary` convention ([Conventional Commits](https://www.conventionalcommits.org/)) as the individual commits, e.g. `fix: ...`, `feat: ...`, `ci: ...`. +- The PR title becomes part of the auto-generated release notes for whichever package(s) it touches (`.release-it.base.ts` scopes each package's changelog via conventional commits) — a `chore:` title on a PR that actually fixes something means that fix never shows up in anyone's changelog. +- Body: a short `## Summary` (1-3 bullets, what changed and why it was needed — not a file-by-file listing the diff already shows) plus a `## Test plan` checklist of what was actually run. Skip sections that would just restate the diff. +- Don't repeat the same information across every commit in the PR *and* the PR description *and* a summary comment — pick the level (usually the PR description) and let the rest stay terse. +- When reviewing someone else's PR description for terseness, flag sentences that only restate a line from the diff without adding reasoning, and padding like "This PR also includes minor cleanup" with nothing concrete after it. + +## Code comments + +Default to no comment. Well-named functions and variables already say *what* the code does. Only add a comment when it carries information the code can't: +- a non-obvious constraint or invariant (e.g. why `isFloatRange` treats a range as float if *either* bound is float — that's explained in its own JSDoc because RFC 8610 leaves the mixed case undefined, not because the code alone would tell you) +- the reason for a workaround, ideally with a link to the issue/RFC section that explains it +- behavior that would genuinely surprise a reader + +One line is almost always enough. If removing a comment wouldn't leave a future reader confused, remove it. diff --git a/.gitignore b/.gitignore index 9c32086..d3467c3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ build/ # Generated code __output__/ + +# personal, per-tool agent config - never committed +.claude/ diff --git a/AGENTS.md b/AGENTS.md index 061ad3a..86b4a5a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,9 +1,81 @@ -# Cursor Cloud specific instructions - -- This repository defines a repo-level cloud agent environment in `.cursor/environment.json`. -- The corresponding `.cursor/Dockerfile` pins Node 24 and pnpm 10.32.1, then preinstalls the pnpm workspace dependencies into `/workspace`. -- You can run these commands immediately in a fresh cloud agent without a preliminary `pnpm install`: - - `pnpm compile` - - `pnpm run test:typechecks` -- For focused Vitest runs, disable coverage so single-file or narrow test selections are not blocked by the repo's global coverage thresholds: - - `pnpm exec vitest --config vitest.config.ts --run --coverage.enabled=false packages/cddl/tests/parser.test.ts` +# AGENTS.md + +Entry point for coding agents in this repo. See [.agents/README.md](.agents/README.md) +for available skills — read a skill's `SKILL.md` when its description matches +the task, don't duplicate its rules here. + +No tool-specific agent config is committed beside `.agents/` — permissions, +hooks, and other per-tool settings (e.g. `.claude/`) stay personal and local, +never added to this repo. A thin adapter file like `CLAUDE.md` is the one +exception: it only points here, it doesn't hold its own copy of these rules. + +## Repo map + +pnpm workspace, no lerna/nx. `cddl` is the CDDL parser every other package +depends on (via `workspace:*`); the four `cddl2*` packages are independent +generators built on top of it: + +``` +packages/cddl CDDL → AST parser, shared by every generator below → npm: cddl +packages/cddl2ts AST → TypeScript generator → npm: cddl2ts +packages/cddl2java AST → Java generator → npm: cddl2java +packages/cddl2py AST → Python generator → npm: cddl2py +packages/cddl2swift AST → Swift generator → npm: cddl2swift +packages/cddl2kotlin AST → Kotlin generator → npm: cddl2kotlin +examples/ real-world CDDL specs (webdriver-bidi) used across every package's tests +``` + +Each package has its own `.release-it.ts` (sharing common config from +`.release-it.base.ts`) and version — there is no monorepo-wide version to +keep in sync. + +## Setup + +Node 24, pnpm pinned in `package.json#packageManager`. + +```sh +pnpm install +pnpm run compile # compiles cddl first, then every other package (they depend on its build output) +``` + +### Cursor Cloud + +This repository defines a repo-level cloud agent environment in +`.cursor/environment.json`. The corresponding `.cursor/Dockerfile` pins Node 24 +and pnpm 10.32.1, then preinstalls the pnpm workspace dependencies into +`/workspace`. You can run these commands immediately in a fresh cloud agent +without a preliminary `pnpm install`: +- `pnpm compile` +- `pnpm run test:typechecks` + +## Test selection + +Don't default to `pnpm run checks:all` — it's compile + typechecks + unit +tests + cli-examples across every package. Prefer the smallest proof: + +| Change | Run | +|---|---| +| One package's `src/` (not `cddl`) | `pnpm exec vitest --config vitest.config.ts --run --coverage.enabled=false packages//tests/.test.ts` — coverage is disabled here since a single-file selection otherwise gets blocked by the repo's global coverage thresholds | +| `packages/cddl/src` (the shared parser) | every `cddl2*` package depends on its output, so run the full suite: `pnpm run test:unit` | +| Root config, or more than one package | `pnpm run checks:all` | + +There is no lint step configured in this repo. + +## Releases + +Manual, via the "NPM Publish" GitHub Action +([.github/workflows/publish.yml](.github/workflows/publish.yml)) — never +automatic on merge. `cddl` always releases first, in its own job, since every +`cddl2*` package depends on it via `workspace:*`; the rest release afterward +as a sequential matrix (and are skipped entirely if `cddl`'s release job +fails). Selecting `package: all` auto-detects and releases only packages +changed since their last release tag (a shared-`tsconfig.json`-only change +still counts, since `.release-it.base.ts` scopes every package's changelog to +include it); picking one package explicitly always releases it regardless of +whether it changed. + +## Working agreement + +Commit messages, PR descriptions, code comments, and how to stage changes: +see the [concise-writing](.agents/skills/concise-writing/SKILL.md) skill — +same "why, not what" rule across all of it. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2638049 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,4 @@ +# Claude Code + +Follow [AGENTS.md](./AGENTS.md). It is the canonical agent guide for this +repository. Do not add a second copy of those rules here. From e9f6f3b6d69d7182ef39c4dd6b633a831ed1432e Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Tue, 22 Sep 2026 18:06:28 -0400 Subject: [PATCH 2/3] docs: fix generator count in AGENTS.md repo map Said "four cddl2* packages" while listing all five (cddl2ts, cddl2java, cddl2py, cddl2swift, cddl2kotlin). Co-Authored-By: Claude Sonnet 5 --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 86b4a5a..3e9b328 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,7 +12,7 @@ exception: it only points here, it doesn't hold its own copy of these rules. ## Repo map pnpm workspace, no lerna/nx. `cddl` is the CDDL parser every other package -depends on (via `workspace:*`); the four `cddl2*` packages are independent +depends on (via `workspace:*`); the five `cddl2*` packages are independent generators built on top of it: ``` From 3529f8b01588f1084d05db0dbf8904fd697989a3 Mon Sep 17 00:00:00 2001 From: dprevost-perso Date: Tue, 22 Sep 2026 18:07:00 -0400 Subject: [PATCH 3/3] docs: list the complete commit-type set in the concise-writing skill Omitted perf, style, revert, and ops - all four are recognized by .release-it.base.ts's changelog config (perf gets its own "Performance" section) and would produce less accurate release notes if a commit got classified under some other type instead. List the exact set the release config maps, not an arbitrary subset. Co-Authored-By: Claude Sonnet 5 --- .agents/skills/concise-writing/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/concise-writing/SKILL.md b/.agents/skills/concise-writing/SKILL.md index 4fd937a..1581667 100644 --- a/.agents/skills/concise-writing/SKILL.md +++ b/.agents/skills/concise-writing/SKILL.md @@ -24,7 +24,7 @@ fix: generators emit wrong numeric type for floating-point ranges (#78) - One line, imperative mood, `type: summary`, no trailing period. - Lead with *why*, not a mechanical restatement of the diff (bad: "update index.ts"; good: "isFloatRange misclassified symbolic range bounds as float"). - Only add a body if the one-liner genuinely can't carry the reasoning — this repo's history mostly skips it, but a fix that isn't self-explanatory from the summary alone (e.g. it traces back to an RFC section, a specific bug repro, or a non-obvious root cause) earns one. Keep it to what a reader actually needs, not a walkthrough of the diff. -- Pick the type by what changed: `fix`, `feat`, `test`, `ci`, `docs`, `chore`, `build`, `refactor`. +- Pick the type by what changed: `fix`, `feat`, `perf`, `test`, `ci`, `docs`, `chore`, `build`, `refactor`, `style`, `revert`, `ops` — the exact set `.release-it.base.ts` maps to changelog sections. **Staging**: stage specific files by name (`git add path/to/file`), never a blanket `git add -A` or `git add .` — this repo's `.github/workflows/` files touch tokens and publish credentials, and a blind add risks scooping up something that doesn't belong. Check `git status` first for anything unexpected or secret-looking (`.env`, `credentials.json`, `*.pem`, `*token*`) and flag it instead of silently staging it.