Instructions for AI agents and contributors working in the @alpacahq/alpaca-ts-alpha
package.
@alpacahq/alpaca-ts-alpha is a TypeScript SDK for the Alpaca Trading API
and Market Data API. The REST clients/models are generated with OpenAPI
Generator via the reproducible pipeline in tooling/ (npm run generate);
they stay a faithful snapshot of Alpaca's OpenAPI spec, and every convenience is
hand-written in separate modules (see the first convention below). Crucially,
the generated trees are never hand-edited — every required deviation from
stock generator output is encoded declaratively in forked Mustache templates or
JSON Patch overlays, so regeneration reproduces the committed trees byte-for-byte.
See tooling/GENERATION.md for the full design. Notable behaviors to preserve
when editing:
- null-safe array deserialization (no NPE on
nullarray fields), - opt-in retry/backoff (
retry), request timeouts (timeoutMs), defaultUser-Agent, - typed
ApiErrorparsing the{ code, message }envelope, - undocumented-field passthrough on key trading models,
- a
paginationhelper, and avitesttest suite.
- Generated vs hand-written — never hand-edit the generated trees. The
src/trading/{apis,models,index.ts}andsrc/market-data/{apis,models,index.ts}trees are generator output, reproduced bynpm run generate(seetooling/). Treat them as derived artifacts: never hand-edit them. If you need to change generated output, change the spec/overlay/template intooling/and regenerate —npm run generate:offlinemust reproduce the trees byte-for-byte. All behavior, ergonomics, and fixes live in hand-written modules outside those trees (src/client.ts,src/orders.ts,src/marketDataShapes.ts,src/core/runtime.ts,src/streaming/, ...). - Regeneration-safe customizations live in
tooling/. Three deviations from stocktypescript-fetchare encoded declaratively so they survive every regeneration: (1) null-safe required-array deserialization — forkedtemplates/typescript-fetch/modelGeneric.mustache; (2) undocumented-field passthrough on 6 trading models —x-ts-passthroughvendor extension (trading overlay) + forked templates; (3) market-datafeedenum tightening — market-data overlay. Add new fixes the same way (template or overlay), never as a hand-edit. - The transport is shared. The HTTP transport (retry/backoff, timeouts,
rate limiting, typed errors, middleware, querystring, response wrappers) lives
once in
src/core/runtime.ts.src/trading/runtime.tsandsrc/market-data/runtime.tsare thin shims thatexport *from it and only add their host constants plus aConfigurationsubclass overridingdefaultBasePath(). Make transport changes insrc/core/runtime.ts; touch the shims only for host/base-path concerns. These shims sit inside the generated trees but are hand-maintained transport code, protected from regeneration by.openapi-generator-ignore; treat them as the hand-written exceptions inside those otherwise generator-owned trees. - Edit
src/directly for behavior changes. - Keep the capability maps in sync. When you add an ergonomic helper to
TradingClient/MarketDataClient/OrdersApi(src/client.ts), add it toergonomicCapabilitiesinsrc/capabilities.ts— a test intest/client.test.tsasserts every listed helper exists on the facade. - Linting is scoped to hand-written code. Biome (linter only; formatter and
assist are off) lints the hand-maintained TypeScript. The OpenAPI-generated
src/trading/{apis,models,index.ts}andsrc/market-data/{apis,models,index.ts}are excluded inbiome.json— they're generator output, so don't lint or hand-edit them. - Keep the test suite green and add coverage for new behavior.
npm install # also builds via the `prepare` script
npm run build # tsup -> dist/ (dual ESM + CJS)
npm run typecheck # tsc --noEmit (the type authority)
npm test # vitest
npm run lint # biome lint (hand-written code; generated apis/models are ignored)
npm run lint:fix # biome lint --write (apply safe autofixes)
npm run generate # regenerate REST trees: fetch latest specs, diff, confirm, generate
npm run generate:offline # reproduce the trees from pinned specs (no network)Regeneration lives in tooling/ (a separate private package with its own deps
and tests). It needs a real JDK (auto-detected; brew install openjdk if
missing). See tooling/GENERATION.md for the pipeline, durability mechanisms,
and how to adopt upstream spec changes.
Releases and CHANGELOG.md are managed with Changesets.
Changelog entries are human-authored, decoupled from commit messages — every
user-facing change ships with a changeset file describing it and its semver bump.
npm run changeset # add a changeset: pick patch/minor/major + write the summary
npm run changeset:version # consume changesets -> bump version + update CHANGELOG.md
npm run release # build, then `changeset publish` (npm publish + git tag)Workflow:
- Per change: run
npm run changeset, choose the bump (patch/minor/major), and write a one-line, user-facing summary. Commit the generated.changeset/*.mdfile alongside the code change. Internal-only changes (CI, tooling, refactors with no consumer impact) need no changeset. - At release time: run
npm run changeset:version. This applies all pending changesets, bumpsversioninpackage.json, regeneratesCHANGELOG.mdwith GitHub PR/commit links (via@changesets/changelog-github), and deletes the consumed changeset files. Review and commit the result. - Publish: run
npm run releaseto build and publish to npm, then push the commit and the tag (git push --follow-tags).
Notes:
@changesets/changelog-github(configured in.changeset/config.json) needs aGITHUB_TOKENenv var when runningchangeset:versionso it can resolve PR/commit/author links — e.g.GITHUB_TOKEN=… npm run changeset:version.accessispublicin.changeset/config.json(the package is scoped@alpacahq/*).- The existing
v0.1.0–v0.2.0releases predate this setup and are intentionally not backfilled; the changelog starts from the next release.
The pipeline is interactive and has a few human-judgment gates. When assisting, act as the analyst between steps: run observable previews, interpret each output, recommend a decision, and let the human own the irreversible calls.
- Division of labor. Human owns: adopting a fetched spec as the new baseline, accepting API surface changes, and the final commit. Agent owns: running previews, classifying the spec diff, proposing overlay/template fixes, mapping orphaned exports to hand-written references, and verifying the byte-for-byte invariant.
- Don't block on the prompt. The confirm step reads stdin and will hang a
non-interactive shell. Gather context non-interactively instead:
- Preview live changes without writing:
npm run generate -- --dry-run --yes(prints the spec diff + plan;--dry-runguards every write,--yesonly skips the prompt). - Reproduce/verify from pinned specs:
npm run generate:offlinethengit diff -- src/trading src/market-data. - Iterate on one API: add
--target tradingor--target market-data. - Only run an adopting generation (
npm run generate, or… -- --yes) after the human approves the diff.
- Preview live changes without writing:
- Interpret each output and surface it.
- Spec diff (
schemas +/-/~,operations +/-): classify additive vs breaking. Removed/renamed schemas or operations, or modified shapes on models the facade wraps, are potentially breaking — name them. Pure additions are low-risk. OverlayDriftError … <op> <path>: an overlay target moved upstream. Locate where the field/parameter went intooling/specs/<api>.jsonand propose the updated op intooling/overlays/<api>.patch.json; re-run--offlineto confirm.removed stale …: a schema/operation disappeared; confirm it's intended and grep the symbol in hand-written code.- Orphan report (
exports removed): for each removed symbol, searchsrc/client.ts,src/orders.ts,src/marketDataShapes.ts,src/capabilities.ts, andsrc/streaming/and fix references before committing. - Final
git statuson the trees: the target is no diff except deliberate changes. Unexpectedapis//models/churn means a spec change was adopted — confirm it's intended and reflected in tests/ergonomics.
- Spec diff (
- Failure playbook.
- No JDK:
brew install openjdk(keg-only; the pipeline finds it). - Non-empty diff after
--offlinewith no spec change: a template/overlay regression — reconcile the template/overlay, never the generated file. - Safety gate fails (typecheck/lint/test/docs): a real regression; new API
surface usually means new ergonomics, an out-of-date capability map
(
src/capabilities.ts), or stale docs.
- No JDK:
- After a successful adopt. For new operations/models, consider ergonomic
helpers on
TradingClient/MarketDataClient/OrdersApiand keepergonomicCapabilities(src/capabilities.ts) in sync. Commit the regenerated trees together with the updatedtooling/specs/*and anytooling/overlays/*so the baseline stays reproducible.