Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .agents/README.md
Original file line number Diff line number Diff line change
@@ -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.
57 changes: 57 additions & 0 deletions .agents/skills/concise-writing/SKILL.md
Original file line number Diff line number Diff line change
@@ -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`, `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.

**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.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ build/

# Generated code
__output__/

# personal, per-tool agent config - never committed
.claude/
90 changes: 81 additions & 9 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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

Comment thread
dprevost-LMI marked this conversation as resolved.
Resolved
pnpm workspace, no lerna/nx. `cddl` is the CDDL parser every other package
depends on (via `workspace:*`); the five `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/<pkg>/tests/<file>.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.
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -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.
Loading