AvelonDocs

Guide 10

Conventions

10. Conventions

Vocabulary

One coherent world, so names are guessable once you know the theme.

ConceptNameWhy
The frameworkAvelonthe isle where the wounded king is carried to rest and heal
CLIreevethe official who administers a place on behalf of its lord
Model layerScrivenerthe one who writes the records
Row access rulesWarda thing kept under protection
Background workErranda task sent out to be done elsewhere
Queue dashboardVigila watch kept
Debug and introspectionLanternsee into a dark place
RealtimePealbells carrying across a distance
API tokensSignetthe seal that proves who sent it
Feature flagsBannerraised or not
Architecture linterBailiffthe officer who keeps order
Test harnessAssayto test a material for what it really is
Local environmentHearthwhere the work happens
Admin panelMootthe assembly where matters are settled

Names not on this list are descriptive on purpose: Controllers, Models, Policies, Events, Listeners, Middleware, Requests. Cleverness in a name is a tax paid by every new reader, and it is only worth paying where the concept is genuinely new.

Under a scope, none of these need availability checks. @avelon/scrivener is yours the moment the scope is.


TypeScript

  • strict plus noUncheckedIndexedAccess.
  • No any in an exported signature. unknown plus a narrowing function is almost always right.

any is permitted only at a vendor boundary inside a driver package, with a comment naming what it bridges.

  • Prefer type inference at call sites and explicit types at boundaries. Every exported function

annotates its return type.

  • interface for contracts, type for unions and mapped types.
  • Const assertions on configuration and capability objects, because capability narrowing depends on

literal types surviving.

  • No enums. Union of string literals.
  • Errors extend the framework taxonomy. A bare throw new Error() in framework code is a lint error.

Formatting

Prettier with the shipped config. Not configurable per project, because the point of shipping a config is that nobody spends a meeting on it.

{
  "semi": false,
  "singleQuote": true,
  "printWidth": 100,
  "trailingComma": "all"
}

Do not reformat files you are not otherwise changing. Do not open formatting-only pull requests.


Comments

Comment the non-obvious "why," never the "what."

// Bad
// Loop over the posts and map them to views
const views = posts.map(PostView.make)

// Good
// PostgREST caps embeds at two levels, so the third relation loads separately.
const comments = await Comment.query().whereIn('post_id', ids).get()

A comment explaining a workaround must name what it is working around. A comment restating the code is deleted on sight.


Documentation standard

Modeled on the register of yannelli/attempt: hierarchical sections, progressive complexity, method reference tables, abundant realistic code, and instructional voice.

Voice. Second person, present tense, instructional. "You may configure the retry count with tries." Not "the developer can optionally set." Not "we recommend."

Structure. Every package README, in this order:

1. Introduction. What it does and when to reach for it, in under five sentences. 2. Installation. One command, plus any required configuration. 3. Basic Usage. The smallest complete example that does something real. 4. Feature sections. One per capability, ordered simple to advanced. 5. Method Reference. A table of every public method, its signature, and a one-line description. 6. Testing. How to test code that uses this package, including the fake.

Code examples. Real and runnable. No foo, no doSomething(), no ellipses standing in for the interesting part. Every example parses as TypeScript.

Tables. Used for method references, capability matrices, and option lists. Not for prose.

Enforcement

  • reeve make:package scaffolds the structure.
  • reeve docs:check fails a package when a public export is missing from the Method Reference table,

a code block does not parse, or a required section is absent without an explicit waiver.

  • The docs site consumes the same source, so a package README and its docs page cannot drift.

Packages in a living ecosystem read alike when the docs set a register and a lint pass holds it. That is a deliverable, not a hope.


Commits and branches

  • Conventional commits scoped to the package: feat(orm): eager load via query IR
  • One work package per branch
  • The pull request body states which acceptance criteria passed
  • Never commit .env, a service role key, or a real project reference