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
20 changes: 20 additions & 0 deletions .claude/skills/prepare-regen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Prepare Repo for Fern SDK Regeneration

Triggers: prepare regen, prepare for regeneration, prep for fern, new sdk gen, prepare sdk gen

## Steps

Read AGENTS.md for full context on the regeneration workflow and freeze classification rules.

1. Fetch latest `main` and create a new branch: `lo/sdk-gen-<YYYY-MM-DD>` (use today's date).
2. Push the branch to origin.
3. Create an empty commit (`chore: initialize SDK regeneration branch`) if needed, then create a PR titled `chore: SDK regeneration <YYYY-MM-DD>`.
4. Read `.fernignore` and classify each entry using the rules in AGENTS.md:
- **Permanently frozen**: entirely hand-written, no Fern equivalent. NEVER touch these.
- **Temporarily frozen**: Fern-generated with manual patches. These get swapped.
5. For each **temporarily frozen** file only:
- Copy the file to `<filename>.bak` alongside the original.
- In `.fernignore`, replace the original path with the `.bak` path (protects our patch, lets Fern overwrite the original).
6. Stage the updated `.fernignore` and all `.bak` files.
7. Commit as `chore: unfreeze files pending regen` and push.
8. Report the PR URL and confirm the branch is ready for generator output.
22 changes: 22 additions & 0 deletions .claude/skills/review-regen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Review Fern SDK Regeneration

Triggers: review regen, review regeneration, diff regen, compare regen, post regen review

## Steps

Read AGENTS.md for full context on the regeneration workflow and freeze classification rules.

1. Find all `.bak` files in the repo — these are our pre-regen manually-patched versions (protected by `.fernignore`).
2. For each `.bak` file, diff it against the corresponding newly generated file to show what changed.
3. Identify which manual patches are still needed (the `.bak` has changes the generator doesn't produce).
4. Present a summary of findings to the user, grouped by category:
- Patches no longer needed (generator now handles it)
- Patches still needed (must be re-applied)
- New changes from the generator worth noting
5. Wait for user direction on which patches to re-apply.
6. Re-apply confirmed patches to the generated files.
7. In `.fernignore`, replace each `.bak` path back to the original path for files that still need patches.
8. Remove `.fernignore` entries entirely for files where patches are no longer needed.
9. Delete all `.bak` files.
10. Run `ruff check --fix`, `mypy --ignore-missing-imports src/deepgram/`, and `pytest` to verify.
11. Commit as `chore: re-apply manual patches after regen` and push.
5 changes: 5 additions & 0 deletions .fernignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ src/deepgram/transport_interface.py
src/deepgram/transport.py
src/deepgram/transports

# Claude Code agent files
CLAUDE.md
AGENTS.md
.claude

# Folders to ignore
.github
docs
Expand Down
78 changes: 78 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Agents

## Fern SDK Regeneration

### Overview

This SDK is generated by [Fern](https://buildwithfern.com/). Most files under `src/deepgram/` are auto-generated and should not be edited directly. Some files have manual patches and are listed in `.fernignore` to prevent the generator from overwriting them.

When a new Fern generator release is available, we prepare the repo so the generator can overwrite previously-frozen files, then re-apply manual patches after reviewing the diff.

### Freeze classification rules

Every entry in `.fernignore` falls into one of two categories. The **comment above each entry** in `.fernignore` indicates which category it belongs to, but when in doubt, apply these rules:

#### Never unfreeze (permanently frozen)

These files are **entirely hand-written** — they have no Fern-generated counterpart. The generator would delete or replace them with something unrelated. They must stay in `.fernignore` at all times.

How to identify:
- The file was **created by us**, not by Fern (e.g., `src/deepgram/client.py`, custom tests, helpers, transport layer)
- The file is a **doc, config, or folder** we maintain independently (README, CHANGELOG, .github, examples, etc.)
- The file lives **outside `src/deepgram/`** in a hand-maintained location (e.g., `.claude/`, `docs/`)

Current permanently frozen files:
- `src/deepgram/client.py` — entirely custom (Bearer auth, session ID); no Fern equivalent
- `src/deepgram/helpers/` — hand-written TextBuilder helpers
- `src/deepgram/transport_interface.py`, `src/deepgram/transport.py`, `src/deepgram/transports/` — custom transport layer
- `tests/custom/test_text_builder.py`, `tests/custom/test_transport.py` — hand-written tests
- `tests/manual/` — manual standalone tests
- `README.md`, `CHANGELOG.md`, `CONTRIBUTING.md`, `reference.md` — docs
- `CLAUDE.md`, `AGENTS.md`, `.claude/` — agent files
- `.github/`, `docs/`, `examples/` — folders

#### Unfreeze for regen (temporarily frozen)

These files are **Fern-generated but carry manual patches** to fix issues in the generator output. We freeze them to protect our patches between regenerations, but unfreeze them before a regen so we can compare the new output against our patches.

How to identify:
- The file **exists in Fern's output** — if you removed it from `.fernignore` and ran the generator, Fern would produce a version of it
- Our version is a **modified copy** of what Fern generates (e.g., changed `float` to `int`, added optional defaults, broadened a Union type)

Current temporarily frozen files:
- `src/deepgram/speak/v1/socket_client.py` — optional message param defaults, broad exception catch
- `src/deepgram/listen/v1/socket_client.py` — same + `construct_type` for unknown WS messages
- `src/deepgram/listen/v2/socket_client.py` — same
- `src/deepgram/agent/v1/socket_client.py` — same + `_sanitize_numeric_types`
- `src/deepgram/types/listen_v1response_results_utterances_item.py` — `float` → `int` fix
- `src/deepgram/types/listen_v1response_results_utterances_item_words_item.py` — `float` → `int` fix
- `src/deepgram/types/listen_v1response_results_channels_item_alternatives_item_paragraphs_paragraphs_item.py` — `float` → `int` fix
- `src/deepgram/types/listen_v1redact.py` — Union[str, Sequence[str]] support
- `src/deepgram/listen/v1/client.py` — Union[str, Sequence[str]] array param support
- `src/deepgram/listen/v2/client.py` — same
- `tests/wire/test_listen_v1_media.py` — `transcribe_file()` bytes param fix
- `wiremock/wiremock-mappings.json` — removed duplicate stub

### Prepare repo for regeneration

1. **Create a new branch** off `main` named `lo/sdk-gen-<YYYY-MM-DD>`.
2. **Push the branch** and create a PR titled `chore: SDK regeneration <YYYY-MM-DD>` (empty commit if needed).
3. **Read `.fernignore`** and classify each entry using the rules above.
4. **For each temporarily frozen file only:**
- Copy the file to `<filename>.bak` alongside the original.
- In `.fernignore`, **replace the original path with the `.bak` path**. This protects our patched version from the generator while allowing Fern to overwrite the original.
5. **Never touch permanently frozen entries.** Leave them in `.fernignore` as-is.
6. **Commit** as `chore: unfreeze files pending regen` and push.
7. The branch is now ready for the Fern generator to push changes.

### After regeneration

The `.bak` files are our manually-patched versions (protected by `.fernignore`). The original paths now contain the freshly generated versions. By comparing the two, we can see what the generator now produces vs what we had patched.

1. **Diff each `.bak` file against the new generated version** to understand what changed and whether our patches are still needed.
2. **Re-apply any patches** that are still necessary to the newly generated files.
3. **In `.fernignore`, replace each `.bak` path back to the original path** for any files that still need manual patches.
4. **Remove `.fernignore` entries entirely** for any files where the generator now produces correct output (patches no longer needed).
5. **Delete all `.bak` files** once review is complete.
6. **Run tests** (`pytest`) and linting (`ruff check`, `mypy`) to verify.
7. **Commit** as `chore: re-apply manual patches after regen` and push.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md