Operating instructions for AI coding agents working in this repo. Read this and
STRATEGY.md first, every session.
A new capability ships REST route + OpenAPI entry first. SDK and CLI wrappers follow where they earn their place, generated where possible; MCP stays golden-path only. Releases go out as changesets when ready.
index stacking/mempool extras, the stacks-SDK wallet half (except nonce coordination — supported, see packages/stacks/README.md), webhooks format expansion. Shipped code stays; no new investment, no docs prominence. Being on this list is never grounds to delete; that takes usage or dead-code evidence. Unfreeze requires a named external request. Nonce coordination is the carved-out exception: demand-validated (named external request), supported, documented.
- OSS
/v1reads are keyless on a loopback publish;INSTANCE_TOKENgates writes and every/v1request once the API is reachable past loopback. Hosted/v1(api.secondlayer.tools) is keyed:Authorization: Bearerwith an account key (sk-sl_*, envSECONDLAYER_API_KEY). Same prepaid credits as archive bootstrap. Do not add accounts on OSS. Do not add hosted keyless reads. - Cursor format and public
/v1envelope are 1.0 contracts; reorg/cursor tests are sacred. - Decoders read Streams' reader in-process; the HTTP Streams path is guarded by the HTTP == in-process parity test (
packages/api/src/streams/decode-dogfood.test.ts). Do not break either. (The 11 classic decoders —packages/indexerl2 module — moved in-process; sbtc/pox5/bns still read over HTTP until their own pass.) - Never describe product surfaces as L1/L2/L3 layers in docs or comms — Stacks is itself a Bitcoin L2, so the terms confuse users. Say raw (Streams), decoded (Index), your schema (Subgraphs). This also extends to code: no identifier, env var, service, or table may start with
l2/layer2. The decoder service isdecoder(imagesecondlayer-decoder), the dir ispackages/indexer/src/decode/, checkpoints are nameddecode.<event_type>.v<major>, and the checkpoint table isdecoder_checkpoints. - No EVM/multi-chain. No new wallet-side primitives beyond nonce coordination (supported) and what's already frozen.
- States = one const array in the owning package, mirrored by a DB CHECK.
- Transitions = a
defineMachinetable next to the states (packages/shared/src/db/transition.ts). - Every status write goes through
casTransition;null= lost race, log and stop.scripts/ci/status-writes.tsfails CI on new raw.set({ status:/SET statussites (baseline file; shrink it, never grow it). - Derived states ("is live", "is down", "caught up") = one exported pure fn, no inline copies.
- Work directly on
main; push only when the founder asks (every push deploys prod). - Single-line conventional commits; no process labels; version bumps =
chore: version packages. - Always create changesets for changed packages; release via
bun run release. - Prefer delete over refactor when removing deprecated surfaces.
- Calm infrastructure. Short declarative sentences.
- No exclamation points, no emoji, no hype, no "vs Hiro" — generous to the ecosystem.
- Technical precision over marketing language.
- Reversible: decide, note it in the commit, move on.
- Irreversible (cursor format, public API shape, pricing, product naming): explicit founder approval first.
If you change anything that contradicts this file or STRATEGY.md, update the doc in the same change. Stale instructions are worse than none.