Adding a New Module
This is the checklist to follow when creating a new module in the Koder monorepo. The goal is to avoid the drift that produced the kodaverbapoly mess, the bullqueue ambiguity, and the nexusorbit registry-squatting incident.
Before you create the directory
1. Decide which Area it belongs to
Open areas.md and find the Area that matches the nature of the module — not who consumes it. If two or more Areas seem to fit, the module is probably doing two things. Split it into two modules before proceeding.
Red flags that the Area is wrong:
- "It serves everyone" — probably Foundation
- "It is only relevant to X industry" — probably Industry Solutions
- "It is a tool developers use to ship code" — probably Developer Platform
- "It is an end-user productivity tool" — probably Suite
- "It stores or moves data" — probably Data Platform
- "It tells you what is happening inside something else" — probably Observability
2. Decide where it lives — directory and distribution form
The monorepo uses Area-first organization (RFC-001). The directory path encodes what the product is (Area) and how it is delivered (distribution form subdirectory), not what technology it uses.
2a. Is it a product or infrastructure?
Products have end-users (humans who interact with a UI or consume a business capability). They live under an Area directory:
| Area directory | Use when… |
|---|---|
foundation/ |
Cross-cutting capability: identity, payments, security |
suite/ |
End-user productivity: email, storage, design, messaging |
dev/ |
Developer tooling: forge, IDE, terminal, package registry |
vertical/ |
Vertical solution: fintech, health, legal, agro |
Infrastructure has no direct end-user — it is consumed by other modules. It lives under a technologyfunction directory (`ai, infra, observe,
data, core, sdk, lang, linux/`). The rest of this guide does not apply to infrastructure modules.
2b. What is the delivery model?
A product root (<area>/<product>/) contains one subdirectory per delivery form:
| Subdirectory | Delivery model | Who runs it |
|---|---|---|
platform/ |
SaaS — Koder hosts | Koder infrastructure |
app/mobile/ |
Installable app — Android + iOS | User's phone |
app/desktop/ |
Installable app — Linux + macOS + Windows | User's computer |
app/tv/ |
Installable app — TizenOS + WebOS | User's TV |
app/web/ |
Self-hosted web frontend | User's server |
Create only the subdirectories that exist or are actively planned. A pure SaaS engine needs only platform/. A pure mobile app needs only app/mobile/.
app/mobile/ and app/desktop/ are each independent Flutter projects (own pubspec.yaml). When mobile and desktop share most of their UI, a single Flutter project at app/ root (with android/, ios/, linux/, etc. as siblings) is also acceptable — document the choice in the product README.
2c. Does it need the engine + product split?
Ask: *is this going to be a white-label SaaS that third-party customers will license to build their own products on top?*
- Yes → you need two names, two product roots in the same Area directory
(
<area>/<engine>/platform/+<area>/<product>/), and must readengine-product-pattern.mdbefore picking names. Pick both names upfront. Do not defer. - No → one name is fine. Examples of legitimately single-name modules:
products/dev/flow/(git forge),engines/lang/koda(IDE),infra/data/kdb/(database).
Note —
apps/andplatform/are deprecated. Do not create new modules there. They will be dissolved as existing modules migrate to Area directories (RFC-001, Phase 2).
3. Pick the name(s) responsibly
Run these checks before committing to a name:
| Check | How |
|---|---|
| Does a module with this name already exist? | ls foundation/ suite/ dev/ vertical/ apps/ platform/ infra/ ai/ observe/ core/ sdk/ lang/ linux/ data/ | grep -i <name> |
| Does this name collide with a market-recognized brand? | Search GitHub and general web for "<name>" saas and "<name>" software |
| Does it collide with a concept that Koder will want in the future? | Think about what you would want to call a package registry, a queue system, a payment gateway — do not squat on those names |
| Is it a homophone of another Koder product? | Say the name out loud alongside the five nearest Koder products. If you hesitate, pick differently |
| Does it pronounce cleanly in pt-BR, en-US, and es-ES? | Test it |
| Four to six letters? | Five is best |
If you hit two or more "no" answers, pick a different name.
Creating the module
4. Create the directory and initial files
Replace <area> with the Area directory (foundation, workspace, dev, or industry) and <name> with the product name.
For a SaaS product (backend only):
mkdir -p <area>/<name>/platform/{cmd,internal,docs,backlog/{pending,in-progress,done}}For a product with a mobile app:
mkdir -p <area>/<name>/platform/{cmd,internal}
mkdir -p <area>/<name>/app/mobile
# then: cd <area>/<name>/app/mobile && flutter create .For an infrastructure module (no Area, no product split):
mkdir -p <category>/<name>/{cmd,internal,docs,backlog/{pending,in-progress,done}}
# <category> = ai, infra, observe, data, core, sdk, lang, or linuxMinimum initial files (product root <area>/<name>/):
README.mdorREADME.kmd— one paragraph explaining what the module is, who uses it, its AreaSector classification, and which distribution forms exist or are planned. Include a link back to `....docsstack/areas.md`.icon.svg— 512×512 viewBox, follows the Koder icon style rules inCLAUDE.md(no background, 3D gradient, minimal internal details, dominant color per product). Rasterize toicon-256.pngandicon-512.pngwithrsvg-convert.platform/go.mod(if SaaS backend) — module path:module koder.dev/<area>/<name>/platform.app/mobile/pubspec.yaml(if mobile app) — package name:koder_<name>.backlog/pending/001-initial-scope.md— the first backlog ticket.
5. Update the stack catalog
Edit docs/platform/site/index.html and add the new module to the product catalog JavaScript array near the bottom of the file:
{ name: 'NewThing', slug: 'koder-newthing', cat: '<category>', url: 'https://newthing.koder.dev', desc: '...' }Categories currently in use: foundation, data, infra, observe, ai, devplatform, workspace, industry, brand, saas. Use the closest match.
6. Update areas.md
Add the new Sector row under the correct Area. If it is an engine + product pair, add both rows.
7. If it is a multi-tenant SaaS with an engine + product split
Also update engine-product-pattern.md — add a row to the "Established pairs" table.
DNS and server setup (optional, only when you are ready to publish)
8. Create DNS records
# From k.lin (only IP allowed by ClouDNS for the koder.dev zone)
ssh rodrigo@181.191.210.127 -p 220 'curl -s "https://api.cloudns.net/dns/add-record.json?auth-id=52394&auth-password=XS4gsnjQqRWJ&domain-name=koder.dev&record-type=A&host=<name>&record=181.191.210.127&ttl=300"'9. Add the site to koder-jet
Edit /etc/koder-jet/sites.toml on k.lin:
[[sites]]
domains = ["<name>.koder.dev"]
root = "/var/www/<name>.koder.dev"
gzip = trueCreate /var/www/<name>.koder.dev/ with at least an index.html placeholder, then sudo systemctl restart koder-jet.
10. Deploy the landing page
Follow the rules in CLAUDE.md:
- Landing page lives inside the module repo (
platform/<name>/site/orapps/<name>/site/), never in the separatesites/directory - Always publish and announce the URL in the chat when you finish
- Use HTTPS only, no HTTP
- Keep default theme (light/dark) with system preference detection
Committing your work
11. Clean the index before staging
Critical rule for the monorepo — always run this before your first git add:
git reset HEADThis prevents parallel sessions' staged files from being swept into your commit. See feedback_monorepo_parallel_sessions.md in global memory for the incident that motivated this rule.
12. Stage only your files explicitly
git add platform/<name>/ docs/stack/areas.md docs/platform/site/index.htmlNever use git add -A, git add ., or git add <wide-path>/.
13. Verify what is about to be committed
git diff --cached --statIf you see files from directories you did not touch, stop and rerun git reset HEAD then re-stage.
14. Commit with a descriptive message
Follow the repo's commit style (<scope>: <summary> on the subject line, brief body explaining what and why). Always include the co-author trailer per CLAUDE.md.
15. Push and follow the release flow
If the module is a shippable product, invoke /com_rel_syn_dpl after the commit to handle release packaging, tagging, and distribution.
Post-creation checklist
- [ ] Area assignment added to
areas.md - [ ] Icon follows Koder visual family (3D gradient, no background, unique dominant color)
- [ ] README.md explains the module's identity in one paragraph
- [ ] Ecosystem catalog (
docs/platform/site/index.html) updated - [ ] If engine + product split applies: both modules created, both names registered in
engine-product-pattern.md - [ ] DNS record created (only if publishing a site)
- [ ]
koder-jetsite entry added (only if publishing a site) - [ ] Landing page deployed and URL announced in chat
- [ ] Commit made with clean index and explicit file list
- [ ] No parallel-session files accidentally included in the commit
When all boxes are checked, the module is a first-class citizen of the Koder Stack.