Agent guide#
This file is mirrored to Dosu (page
6e69465b-8afd-4278-92cf-5aa2d416b6e2, deployment "Mag Stacker MCP Server") so it's queryable viadosu ask/ the Dosu MCP. The page is a static snapshot β after editing this file, refresh it:dosu docs update 6e69465b-8afd-4278-92cf-5aa2d416b6e2 --body-file ./AGENTS.md.
Canonical project docs (read these first)#
The authoritative descriptions of the stack, structure, and product live in the
Kiro steering docs. Every agent β Kiro or otherwise β should treat them as the
source of truth; this file only adds the agent boundaries and the few
operational details not covered there.
.kiro/steering/tech.mdβ the stack, the non-default tooling (Bun, Biome,
taplo, mise), and the fulljustcommand table (dev, lint, format,
typecheck, test, build, db,ci-check)..kiro/steering/structure.mdβ repo layout and the layered server-side
flow (route pages β server actions β pure domain validators β auth/visibility
β db), plus the feature-slice conventions for adding code..kiro/steering/product.mdβ what MagStacker is, who it's for, the
owner-scoping / grant-sharing core rules, and the "Machined Console" design
identity.CONCEPTS.md(repo root) β domain glossary: entities, sharing/visibility
model, classification & labeling, derived values. Canonical names for domain
concepts.docs/solutions/β solutions to past problems (bugs + knowledge),
organized by category with YAML frontmatter (title,category,module,
problem_type,component,severity,tags); relevant when implementing
or debugging in a documented area.
Stack at a glance (see .kiro/steering/tech.md for detail): TypeScript Β·
Next.js 16 (App Router) Β· React 19 Β· Bun Β· Biome (not ESLint/Prettier) Β·
Tailwind v4 Β· Postgres + Drizzle (pg Pool) Β· Better Auth Β· Docker Β· multi-user
owner-scoped inventory + grant-based sharing (all shipped).
Operational details (not in steering)#
- Hooks: never wire ESLint/Prettier/pnpm hooks here β use
bun biome check,bun biome format,bun tsc --noEmit. - Auth specifics:
disableSignUp: trueβ accounts are created server-side viaauth.api.createUser(seescripts/seed-admin.ts); admin plugin; DB-stored rate limit (/sign-in/email= 5/60s). Session cookie:better-auth.session_token. BETTER_AUTH_URLmust equal the request origin or Better Auth returns 403 "Invalid origin".mise.toml(env_cache=true,_.file=['.env','.env.local']) injects env vars stickily (default:3000) β override explicitly when serving on another port.DATABASE_URLis read byrequireDatabaseUrl()(src/db/client.ts) and is not in.env.exampleβ supply it. User delete CASCADEs children.- Testcontainers detail:
bunfig.tomlpreloadssrc/test-support/preload.ts, which starts a migrated ephemeral Postgres and exportsDATABASE_URLbefore any test module loads; the pinned image lives insrc/test-support/postgres-image.ts(single source, also read by CI). Never reintroduce aprocess.env.DATABASE_URL ? describe : describe.skipgate β that idiom silently skipped the whole integration suite whenever the variable was unset. Reusesrc/test-support/factories.ts, and give a test its own owner rather than asserting over rows earlier tests left behind. - MUST-PASS PRE-COMMIT GATE: You MUST run
just ci-checkand ensure it passes before every commit. Do not commit β for any reason β whilejust ci-checkis failing. No--no-verify, no skipping, no "I'll fix it in a follow-up." A redjust ci-checkblocks the commit.
Workflow & boundaries#
- Git workflow: feature branches + PRs only β never commit directly to
main. Conventional Commits, semver. For agent tasks, prefer an isolated worktree:git worktree add -b ai/<task> .worktrees/<task>(checkgit worktree listfirst; merge and clean up when done). - PRs squash-merge, so the PR title and body ARE the commit message. This repo merges with
squash_title: PR_TITLEandsquash_msg: PR_BODY; every branch commit message is discarded at merge. Therefore:- The PR title MUST be a valid Conventional Commit subject β
<type>[(<scope>)][!]: <description>β since it becomes the subject line onmainverbatim. The scope is optional (docs: β¦is as valid asdocs(agents): β¦). - A breaking change MUST be marked on the PR itself: a
!before the colon in the PR title and aBREAKING CHANGE: <what breaks>footer in the PR body. The!is valid with or without a scope βfeat!: β¦andfeat(scope)!: β¦both work. Marking it only on a branch commit does not work β the marker is destroyed by the squash. A prose "Breaking change" heading in the body is not the footer and does not count. - Releases are cut by pushing a
v*.*.*tag by hand; nothing parses commits to compute the bump, so these markers are the only record of what the next version should be. A merged PR carrying a breaking change means the next tag is a major.
- The PR title MUST be a valid Conventional Commit subject β
- Releases/deploy: container image
ghcr.io/unclesp1d3r/mag_stackervia GitHub Actions; project docs at https://unclesp1d3r.github.io/mag_stacker/. Style/structure reference repo: https://github.com/EvilBit-Labs/hash_hive. - Do without asking: create/delete/rename files, rewrite sections, change dependencies, modify DB schema or Docker config, update docs.
- Ask first: anything touching secrets/credentials, auth logic changes, deleting failing tests.
- Never: skip or disable tests "temporarily".
- Testing preference: favor E2E and integration tests over mocks when possible.
This is NOT the Next.js you know#
This version has breaking changes β APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.