8.7 KiB
Concise Comments
Cap any single comment block at two lines. Most should be one.
- Default to writing no comment. Only add one when the WHY is non-obvious — a hidden constraint, a subtle invariant, a workaround for a specific bug, behavior that would surprise a reader.
- If you're tempted to write a third line, the comment is wrong: either delete it, or replace it with a clearer name / smaller function so the code explains itself.
- Don't restate WHAT the code does — well-named identifiers already do that.
- Don't reference the current task, fix, or callers ("used by X", "added for the Y flow", "handles the case from issue #123") — those belong in the PR description and rot as the codebase evolves.
- This applies to inline
//comments AND JSDoc/docstring blocks. A JSDoc whose summary line + one detail line covers the WHY is fine; a four-line paragraph is not.
If something genuinely needs more explanation, link to a doc or a memory file rather than inlining a wall of text in source.
Autumn Shared Utils
Before writing inline .filter(), .find(), .some(), boolean predicate, or <src>To<dst> transform logic over Autumn objects (Price, Entitlement, FullCusProduct, FullCustomer, Feature, etc.), check autumn/shared/utils/ for an existing helper. Reaching for array.filter(... === id) directly is almost always a sign the utility was missed.
The package is organized resource-first, pattern-second. Within each <resource>Utils/ folder:
classify*/—is*boolean predicates (isPrepaidPrice,isCustomerProductPaidRecurring)convert*/—<src>To<dst>transforms (cusProductToPrices,entToPrice)find*/—Array.findlookups (findFeatureById,findPriceByFeatureId)filter*/—Array.filtercollections (filterCustomerProductsByFeatureId)enrich*files — augment with joined data (enrichEntitlementWithFeature)
If the helper you need doesn't exist, ALWAYS ask the user before adding one. Naming and folder placement are cross-cutting and non-trivial — wrong placement clutters @autumn/shared for every consumer.
Full convention (folder tree, naming nuances, anti-patterns): see the shared-utils skill.
Installing External Skills
Third-party skills installed via bunx skills add <pkg> land under each agent's local skill dir (.claude/skills/, .cursor/skills/, etc.). Those locations are NOT a source of truth — bun ai sync only reads from ai/config/skills/** and prunes anything else it manages, so a raw bunx skills add will not propagate to the other consumer repos (autumn, cloud).
Workflow
- Install via the CLI as usual:
bunx skills add <owner>/<repo> - Move the installed skill folder(s) into
ai/config/skills/external/<skill-name>/.external/is core, so bothautumnandcloudconsume it. Usecloud/external/only if the skill references cloud-only code. - Delete the leftover copies from
.claude/skills/,.cursor/skills/,.agents/skills/,.opencode/skills/—bun ai syncwill recreate them as symlinks. - Run
bun ai syncto symlink the skill into every agent dir across every repo that pulls theai/submodule.
Notes
- Skill folder names must be globally unique across
ai/config/skills/**(sync flattens them). - Keep upstream
SKILL.mdfrontmatter intact —nameanddescriptiondrive when the agent loads it. Only edit if the description is not specific enough about WHEN to use the skill. - If the skill ships a
references/orscripts/subfolder, copy the whole directory tree, not justSKILL.md. - Re-running
bunx skills addupstream-updates: install fresh, diff againstai/config/skills/external/<name>/, then promote the changes.
Scope Cache Refresh Changes Safely
When changing cache-refresh behavior for API routes:
- Prefer editing
server/src/honoMiddlewares/refreshCacheConfigs.tsto add or remove route entries. - Do not remove or bypass logic in
server/src/honoMiddlewares/refreshCacheMiddleware.tsunless the user explicitly asks to change middleware behavior globally. - If the request is ambiguous, ask whether they want a route-level config change or a global middleware behavior change.
Cache Version Increment Policy
Treat cache_version as a DB-side stale-sync guard for syncItemV4, not a general cache mutation counter.
Increment cache_version only when needed
Increment only for DB updates that must not be overwritten by stale sync payloads read from cache (for example lifecycle or billing transitions).
Do not increment on cache-side/runtime patch paths
For runtime balance/reset/cache patch flows, do not bump cache_version in cache writers or Lua update scripts.
Examples:
- FullSubject cache patch helpers (
updateSubjectBalanceCache, reset/deduction cache patch sync helpers) - FullSubject Lua cache update scripts (
updateSubjectBalances) - Update-balance runtime paths that patch Redis and then sync
Call-site rule for CusEntService.update
When using CusEntService.update(...) in runtime FullSubject cache patch flows, set incrementCacheVersion explicitly.
- Use
incrementCacheVersion: falsefor routine balance/reset/adjustment updates that are mirrored to Redis. - Use
incrementCacheVersion: trueonly for intentional DB-side stale-write protection transitions.
Why
Incorrect version bumps create CACHE_VERSION_MISMATCH conflicts in syncItemV4, causing repeated invalidation and stale/lost update behavior.
Legacy exception (review-required)
There is a legacy-compatibility exception in the adjust-balance flow:
adjustBalanceDbAndCachecurrently usesCusEntService.increment/decrement, which incrementscache_version.- Treat this as a reviewable legacy action, not a pattern to copy into new runtime/cache patch paths.
- Any new or refactored runtime balance/reset/cache patch code should continue following this policy and avoid adding new cache-version bumps by default.
Project Context System
Projects maintain state in .context/<project>/ folders across sessions. Tasks are optional parallel workstreams within a project.
Default: NOT interacting with a project
Unless the user explicitly mentions a project or task by name, assume the current conversation is NOT associated with any project. Session-start hooks may surface a list of active projects as reference material — that alone is NOT a signal that the current work belongs to any of them.
Do not:
- Read
.context/**files proactively - Write, update, or append to any project's STATUS.md / DECISIONS.md / sessions
- Assume a script, audit, or change is part of a project just because it touches files related to one (e.g. a user-of-framework script is not part of the framework's project)
Only engage with .context/<project>/ when the user explicitly references the project, opens a task in it, or asks for project-tracking actions.
Reading context (when a project IS referenced)
When the user mentions a project or task name and .context/<name>/ exists:
- Read project STATUS.md first (20-30 line "resume card")
- If the project has
tasks/, list active tasks - If the user mentions a specific task, read
tasks/<task>/STATUS.md - Read the most recent session summary if more detail is needed
- Do NOT read everything upfront. Use progressive disclosure.
Updating context (at breakpoints, NOT continuously)
Only update when the current work IS part of a project (see default-off rule above). When it is, update at these moments ONLY:
- Phase or milestone completed
- Architectural decision made (append to DECISIONS.md)
- User says they're done or switching tasks
- Blocker discovered or resolved
- Task created, completed, or handed off
Do NOT update context during normal coding work. Work first, compact at breakpoints.
A STATUS.md entry should record changes to the project itself -- not one-off work that merely uses the project (e.g. writing a consumer script of a framework is not a framework-project update).
Compaction quality
STATUS.md must be:
- Correct (reflects actual current state, not stale)
- Complete (no critical information missing)
- Concise (project < 30 lines, task < 20 lines)
Always REWRITE STATUS.md completely rather than append.
File structure
.context/<project>/
STATUS.md -- project resume card (includes Active Tasks section)
PLAN.md -- phases and architecture
DECISIONS.md -- append-only decision log
sessions/ -- dated session summaries
tasks/ -- optional parallel workstreams
<task>/
STATUS.md -- task resume card
DECISIONS.md
Task handoff
When a task is being handed to another agent, ensure the task's STATUS.md is up to date -- it's the handoff artifact.