Custom code
Generated SDKs cover the API, but real projects need a little hand-written code too — a convenience wrapper, an extra helper, a tweak to a generated method. Glotto is built so your code survives regeneration. There are two mechanisms:
- The customer-owned extension directory —
lib/in most SDKs andSources/<Module>/Custom/in Swift. Shipped today. - Patch preservation — three-way merge of edits to generated files, in the release PR and (opt-in) locally.
For anything you write from scratch, prefer that extension directory: it’s where preservation is guaranteed.
The customer-owned extension directory
Every generated SDK has an extension directory that is yours. Most engines use lib/; Swift
uses Sources/<Module>/Custom/, inside its conventional SwiftPM target. The contract is
enforced by glotto generate and drift detection the same way for every language:
- Customer-owned, write-if-absent. Glotto seeds the directory once with an entry-point stub, then never overwrites that customer-owned file. Every managed file is regenerated normally, but your extension is left exactly as you left it.
- Excluded from drift. Drift detection ignores customer-owned files on both sides, so an edit there never shows up as drift or blocks a release — the extension is not part of the “regenerate must match” contract.
- A stable import target. The entry-point stub (TypeScript’s
lib/index.ts, Python’slib/__init__.py, Swift’sSources/<Module>/Custom/Custom.swift, …) gives you a fixed place to export from, and its header comment tells you how code you add there reaches the SDK’s surface in that language.
examples/custom-code-lib/inputs — every byte below is sliced from that demo or from one real generate run over it. What Glotto seeds ONCE — src/lib/index.ts, yours from then on
typescript/src/lib/index.ts whole file
// Custom code — never overwritten by `glotto generate`.
//
// This file, and everything else under `lib/`, is yours. `glotto generate`
// writes it once and then leaves it untouched on every subsequent run, and
// drift detection ignores `lib/` entirely — so helpers, overrides, and
// extensions you add here survive regeneration. Re-export them from this entry
// point to keep a single import surface for your custom code.
export {};
066b46389fdd95f09343610f9fdb02d97e8c50f27626cd164f919fe40f029ab8 What Glotto owns — regenerated every run, under the checksum that guards your edits
typescript/src/resources/widgets.ts WidgetsResource.createWidget
createWidget(params: NewWidget, options?: RequestOptions): Promise<Widget> {
return this.core.request<Widget>('POST', '/widgets', { ...options, body: params, contentType: 'application/json' });
} 405b8140007456df5543f12bcfa55e05b969d62b5cefcbe186d4f484ee1bd247 Put helpers, wrappers, and hand-authored code in the extension directory, and it is preserved on every regenerate. Anything you expose from the stub reaches the SDK’s public surface according to that language’s normal package conventions.
Upgrading an existing Swift SDK: if Glotto finds the former
lib/Custom.swiftand no file atSources/<Module>/Custom/Custom.swift, the nextglotto generatecopies its contents exactly to the SwiftPM target and retains the legacy file as a backup for you to remove after review. If both files already exist, Glotto leaves both untouched and prints the paths to reconcile; it never chooses one customer-owned copy over the other.
Every language, on the SDK’s surface: the
lib/machinery (write-if-absent + drift exclusion) is engine-agnostic, every SDK language seeds an entry-point stub, and custom code joins the SDK’s public surface per language: TypeScript and React Native re-export it aslib; Swift compilesCustom/as part of its module; Java, Kotlin, Rust, C#, Dart, and Elixir compilelib/into the SDK artifact; Ruby loads it withrequire "glotto"; and the Go, Python, and PHP stubs document the exact import path to use.
Editing generated files
Sometimes you need to change a generated file directly. Glotto’s rule is simple: it never silently overwrites your edits.
Every generated file carries a checksum comment over the bytes Glotto produced — the
generated-checksum stamped under the emitted pane above is the real one for that file, read out of
the run that produced it rather than written here.
On the next regenerate, Glotto compares that checksum to the file’s current contents. If they match, the file is pristine and is regenerated freely. If they differ, you’ve hand-edited it — so Glotto performs a three-way merge (your version against the old and new generator output) and, on any conflict, writes standard conflict markers and surfaces them in the release pull request for you to resolve, rather than clobbering your change.
How it runs today: the checksum marker ships on every generated SDK language, the release-PR flow does the full three-way merge automatically, and locally
glotto generatepreserves your edited file untouched — or truly merges it when you opt in with--merge. Even the generatedREADME.mdis covered — its checksum rides in an HTML comment that’s invisible in the rendered README, so badges and prose you add survive regeneration. The customer-owned extension remains the simplest home for hand-authored code — no merge to think about at all.
Which should I use?
| You want to… | Use |
|---|---|
| Add new helpers, wrappers, or utilities | The customer-owned extension — always preserved |
| Re-export or extend generated types | The customer-owned extension, importing generated types normally |
| Change the behavior of a generated method | Edit the generated file (preserved; merged in the release PR or with --merge) — or wrap it in the extension |
See Drift detection for how customer-owned files are excluded from the drift gate. The
CLI reference documents the commands that enforce this contract —
glotto generate (whose --force overwrites managed files with local
edits) and drift detection.