🌳
AGENTS.md
1## NEVER Do These
2- **dynamic imports inside functions** EXCEPT `await import(<*sync*.mjs>)` for eps
3- **IGNORE `*-prodPatched.*` files** - build artifacts, not source
4- **UPPER_SNAKE_CASE for constants** - use camelCase: `gracePeriodSec`, `wellKnownDomains`
5- **tmp/scratch files outside `./tmp/`**
6- **constants in throwIf/assertDefined debugCtx** - pass variables (`{foo, bar}`), not strings or `{key: 'literal'}`
7- **run manual `tsc`** - Edit/pt_commit auto-validate
8- **bulk `mv`+`sed` for renames** - use `pt_mv` only (handles all file types + ptAnchorPath + ptAnchorInclude)
9- **bash `rm`/`git rm`** - use `pt_rm` only (ocHook blocks both); pt_rm handles dirs recursively
10- 2>&1
11- inlining instead of DRY single source of truth
13## Bash Tool Summarization
14Outputs >600 tok (`defaultBashSumThresTok`) auto-summarized. Params (undocumented to LLM due to OpenCode bug):
15- **`interest`**: Summary focus; enables memoization (<1hr). Default focus: errors/warnings/status. Use "raw log"/"full output"/"unsummarized" to skip summarization.
16- **`summarizeAboveTokCnt`**: Override threshold.
17- bash cmds are memo'd use `# bump1` to bypass / new cachekey
18- memoization is best-effort (exact-cmd match, <1hr) — a miss executes fresh (signalled via args.description, never command text); never hand-write `: # refocus`/`memo *:` args (hook rewrites commands itself; imitation throws)
20## Tools & Aliases
21- `ptnode` instead of `node` silences hard-to-supress noisy warnings etc
22- `corepack pnpm`
23- **Cluster CLI aliases**: `vultrk`, `minik`, `harv3demo`, `harv2demo`, `do1demo` - each is a separate cluster with its own CLI
24- **MCP tools (`pt_*`)** require OpenCode reload after editing
25- **`pt_seance`** - chat with past session. Output → Task tool.
26- **Auto-committing tools**: `pt_mv`, `pt_rntok` (MCP), `ptm subst`, `ptm extract` (CLI) - don't manually commit after using these
27- **`ptm`** - CLI for refactoring ops
29## Import Boundaries
30- Enforced by `pt_check`/`pt_commit` - violations block commit with details
31- Key: `sharedF`/`componentsF` can't import `serverF`/`deployF`/Node built-ins; package restrictions exist for @kubernetes/client-node, next/, @aws-sdk/, ethers/
32- Runtime resolvers (`server/queries|lib|resolvers|type_resolvers|mutations/`) can't import heavy deployF hub files (eptMjsRunner, doSync*, mkjob, *Runner, ptDeployActions, dockerActions, cliF/) - pulls in massive dep tree → webpack RangeError on bundle. Use small leaf files (e.g. `*AI.mts`) instead.
33- Webpack-bundled files (transitively imported by a `pages/` entry) are checked for Node-only packages (@kubernetes/client-node, @aws-sdk/) via import-graph BFS — type-only imports (`import type`) are excluded
34- Package.json bloat: deps declared in a parent `package.json` but only imported in a single F-suffixed subdir are flagged by `findPkgJsonBloat` (in `pkgBloatAI.mts`); the `no-pkg-json-bloat-in-pt0` test locks this invariant. Move such deps to the subdir's own `package.json`.
36## Edit Ordering
37- **Create exports before imports** - dependency-first, not consumer-first. Todo isn't done until it compiles.
39## Code Style
40- Prefer monorepo-unique variable names over generic (`cliFmt` not `format`, `userEmail` not `email`)
41- **Error handling**: (1) TS guards `assertDefined(x)` best; (2) `throwIf(() => !x, {context})` good; (3) raw `if (!x) throw` avoid. Re-throwing caught errors is fine. Second arg to throwIf is debug context, not a message.
42- Use `||=` and `??=` for assignment: `cache[key] ||= computeValue()` not `if (!cache[key]) cache[key] = computeValue()`
43- Use top-level `await` with normal imports, not `import().then()` wrapper pattern
44- Use `import * as _ from 'lodash-es'` in .mts files (not default import) to avoid TS errors
45- Use existing utilities: `sleepF.mts`, `libChalkF.mts` for terminal colors, `luxNow()` over `LuxDt.now()`, `betLog({varName})` for logging
46- **Multi-key declarations on one line** when short: `const a = 1, b = 2` - but don't chain statements with `;` to reduce LOC
47- **Prefer `genContext` over param passing** for config flowing through multiple layers - `ctx.enterWith()` at entrypoint, `ctx.getStore()` in inner functions
48- **Never add comments** - code should be self-documenting; only comment non-obvious footguns
49- **Extensionless CLI scripts** (e.g., `path_bin/ptnode`): keep minimal, just import+call from a `.mjs` file
50- **Function names must differ from filenames**: use `F` or `AI` suffix on filenames (e.g., file `fooF.mjs` exports `foo`) - function/var/class/method names ending in `AI` are blocked by `pt_check` (`- no-fn-ai-suffix`)
51- **Never re-export** except from [index|common|mutationsF|queriesF].[mjs|mts]
52- **No GQL op names** - `query {` not `query GetFoo {`
54## AI-Generated Code
55- **3+ lines of new logic** → extract to `*AI.mjs`/`*AI.mts`/`*AI.jsx`, even inside existing files
56- Always prefer adapting existing code over writing new logic
57- **DRY tokens**: Before adding or matching strings/constants, search for existing definitions. Import instead of duplicating.
59## Testing
60- **Before committing tests**: break code → confirm test fails → restore → confirm passes → commit
61- Add tests for bug-fix *behavior*, not message wording — skip prose/string asserts; a crufty test is worse than none
62- **`runtests --ptenv=testlocal`** starts its own dev server - do NOT start a separate dev server with `devserver_start`
63- **`runtests --ptenv=testprod`** hits the already-deployed instance
65## Opportunistic Improvements
66- [ ] Convert `if (!x) throw` → `throwIf` → TS guard where applicable (skip re-throws)
67- [ ] DRY shared helpers reduce LOC/brittleness
68- [ ] eps should not transitively import code they don't actually need. prune/restructure
69- [ ] Collapse single-use abstractions
70- [ ] Split god files
71- [ ] Flag circular deps
72- [ ] Move misplaced files to correct folder
73- [ ] Improve/tighten TS types
74- [ ] Make hard-to-debug issues fast-fail
75- Never rename: db cols, secrets, env vars, API contracts
77## Git Usage
78- **`pt_commit` only** - never `git commit` directly. If blocked by pre-existing errors, fix those first.
79- **Commit by default** - when completing a task, commit without asking unless there's a reason not to
80- Don't run `git log` to check commit style
81- **Don't run `git status`/`git diff` before `pt_commit`**. pt_commit should autotrack/stage files you edit
82- **NEVER** destructive git (`reset --hard`, `checkout <commit>`, `restore`, `stash`, `revert`, `clean`) w/o explicit user ask
83- **Don't revert unrelated changes** - if `git diff` shows changes unrelated to your current task, leave them alone (they may be intentional uncommitted work)
84- Use short output flags to save context: `git status -s`, `git diff --stat`, `git log --oneline -n5`
85- **Push when handing back** - use `pt_commit push=true` on commit when you're done talking and waiting for user response.
87## Debugging & Maintenance
88- **Check `action=exceptions` first** when debugging prod errors (requires IMAP/SMTP configured, otherwise use `action=logs`)
89- **Before fixing test failures**: check `ptnode <ep> runtests --history` to see if tests ever passed (pre-existing bug vs regression)
90- **Fix tool bugs first**: When a tool fails unexpectedly, fix the tool before re-running or working around.
92## Running Commands
93- **No external timeout for `timedActions`** - they self-time. Let them stream live.
94- **Progress dots** (`awaitrollout ........ ready`): each `.` = 10 sec polling interval
95- **Never await devservers** — bgtask_status + browser to verify
96- Deploy with minimal output: `ptnode somcat/somapp/bin/ep*.mjs apply`
98## Useful One-liners
99- Query a database: `ptnode */bin/epDbSync.mjs dbconsole "SELECT..."` (read-only; `--write` for mutations, `\d table` for schema)
100- Check app logs: `ptnode <ep> logs`
101- **Check prod exceptions**: `ptnode <ep> exceptions` lists recent errors for that deployment, `--show=N` for full context/stack
102- **Grep tool `include` parameter**: Use brace expansion for multiple extensions: `*.{mjs,mts}` not `*.mjs,*.mts`
103- Never manually create k8s YAML files - reuse existing templates like `genericIngressTmpl`, `deploySimpleDf`, etc.
104- **NEVER use raw `kubectl`** - always use entrypoint actions (`ptnode <ep> logs`, `ptnode <ep> pods`, `ptnode <ep> info`)
106## Context Efficiency / Output Format / Communication
107- **Be terse everywhere** - responses, commit messages, code, logs, docs. No preambles, no restating the task, no filler.
108- When summarizing completed work, end the message with `(uncommitted)`, `(pushed)`, or `(clean)` as the very last word
109- When presenting a plan to user, end with estimated `net +/-N LOC` impact
110- Always prefer DRYest / non-brittle / -LOC solutions
111- When proposing solutions, default to reusing existing infrastructure (DRY) over new standalone implementations.
112- always prefer monorepo-relative paths to absolute paths
114- **For timed actions (`testdeploy`, `apply`, `runtests`)**: use bash timeout of 1200s (20min)