Aumik internal handbook
The team's single reference for how Aumik Labs builds: our stack, how to get set up, how we ship, the platform we run on, and the tooling. Pick a card or use the sidebar.
The platform in one diagram
+------------------- aumik-agents (Bun · Mastra) --------------------+
chat | agents + tools · BOOKING service (central) · comms-manager |
widget → | REST: /api/scheduling/{resource}/... · /api/agents/{id}/stream |
(widgets) +----------------+--------------------------------------+------------+
| one booking API for every product | email/SMS/WhatsApp
aumik-ui (web, Tamagui) --+ ▼
apps/* + @aumik/portal --+ Resend · Meta WhatsApp · SMS
aumik-native → aumik-player (DOOH TV player) (orchestrated by Novu)
|
+--------------------+-- shared box (Hetzner · Uncloud) ------------------+
| Postgres 16 + pgvector · Redis 7 · Infisical · Caddy · apps |
+-----------------------------------------------------------------------+How we're organized
Aumik runs in four role tracks. Most people live mainly in one:
| Track | What they do |
|---|---|
| Dev | Scaffold, build, deploy, and migrate Aumik apps. |
| Content | Books, marketing video, and song videos (Tirhut Press, Balmukund). |
| PO | Portfolio + team rituals — standups, milestones, access. |
| Ops | Deploy-time plumbing — secrets, infra. |
Dev onboarding
Getting a new dev or intern productive: access, the lay of the land, and how work actually moves.
1. Get access
- Send your GitHub handle to your PO — you'll be added to the
aumik-labsorg and granted collaborator access on the repos you're assigned to. - You'll be invited to Slack —
#aumik-devis the main dev channel,#standupis where the async daily standup runs. - Clone the repo(s) you own. Always check the brand index for the canonical remote before pushing (a few repos were renamed and some local clones still point at old slugs).
2. Learn the lay of the land
Read the Monorepos page first — most work happens in three runtime-split monorepos, not one-repo-per-app. Then skim the brand index for what exists. Each app/brand may carry its own CLAUDE.md with stack specifics — read it before working in that repo.
3. Roles & how work flows
- Apijay sets direction at the milestone level.
- Aniket (
aniket-j4332, lead dev) breaks milestones into per-repo dev issues, assigns devs, and runs PR review → sign-off → release to prod. - Devs own the implementation on their assigned repos (available evenings IST + flexible).
The flow:
- Milestones / tracking stories live in
aumik-infra, assigned to Aniket. - Aniket creates dev issues kept closest to their repo (per-app repo,
aumik-ui,aumik-native,aumik-agents,aumik-infra), assigns the owner, and tracks them on the board. - The cross-cutting tracking story is the one exception to "closest to the repo" — it lives where the program does.
4. The board
Everything is tracked on Aumik Dev — org Project #9 (github.com/orgs/aumik-labs/projects/9). Columns: Todo → In Progress → In Review → Done. Every dev issue goes here; per-person boards are superseded.
workflow_call, aumik-infra#11.)5. How we sync
- GitHub issue comments are the source of truth — post progress, blockers, and PR/commit links at meaningful milestones (not every step). If substantive multi-step work has no tracking issue, open one.
- Urgent items also go to Slack
#aumik-devwith an @-mention — "urgent" means you're blocking a teammate, a prod incident, or a change others must act on before they deploy. The Slack note points back to the issue. - Daily standup is async in
#standup(Mon–Fri): a prompt goes out in the morning, replies are collated into a digest in the evening. Reply in-thread with Did / Doing / Blocked.
6. The build philosophy
- Clickable HTML prototypes first. A single self-contained clickable HTML mock (hosted at
proto.aumik.co) is the pre-dev design artifact devs build from. - Know what you're building. Shared building blocks (notifications, booking, auth, the portal) are platform foundations — invest and do them right, don't rush. One-off, single-brand features still get simple first cuts.
- Isolate concurrent work with git worktrees rather than switching branches in a shared checkout.
Tech stack
What we build with, and — more importantly — which stack to reach for given the kind of app.
The app stack
The default full-app stack is Tamagui Takeout v2:
| Layer | Tool |
|---|---|
| App framework | One (Vite-based RN + web, replaces Next.js + Expo Router) |
| UI | Tamagui |
| Realtime sync | Zero (Rocicorp) |
| Auth | Better Auth |
| ORM | Drizzle |
| Package manager | Bun (not pnpm/npm) |
Other stacks you'll see:
- Agents (
aumik-agents): Bun · Mastra · Drizzle — the HTTP agent backend. - Cross-platform / TV (
aumik-native): ReNative — uses yarn, not bun (ReNative breaks on bunworkspace:*). - Lovable exports (
aumik-astro,aumik-dev,aumik-food,aumik-cleaning): Vite · React · Shadcn · Supabase — being converted to Takeout v2, with the original Lovable export kept as a read-only reference.
Which stack / where to host — the tier model
Hosting follows the tier of the app, not a one-size template. Each app declares its tier.
Tier A — marketing / SSG-only
No backend. Cloudflare Pages (~$0–5/mo). Promote to Tier B the moment it needs an API or auth.
Tier B — full Takeout apps (web + mobile + auth + realtime) — the default
Uncloud on Hetzner. One shared VPS hosts multiple Aumik apps as Docker services behind Caddy (~$5–20/mo per VPS regardless of app count, until traffic forces a split). Mobile via EAS Build; OTA via Hot Updater. This is the portfolio default for full apps.
Tier C — escape hatch
SST / AWS. Reserved for any single app that demonstrably needs Aurora auto-scaling, AWS-native compliance, or an enterprise contract requiring AWS. Not the default — currently zero apps live here.
Monorepos — what goes where
Three runtime-split monorepos. Pick by runtime, not by product.
| Monorepo | Runtime | Holds | Toolchain |
|---|---|---|---|
aumik-ui | Web (Tamagui/One) | All web UI apps + shared @aumik/* packages (widgets, portal, tsconfig, eslint-config) | bun · Tamagui · Turbo |
aumik-native | ReNative (TV/mobile) | Cross-platform/TV apps — first app aumik-player | yarn · Metro · Turbo |
aumik-agents | Bun · Mastra | Shared AI backend: agents, tools, the booking service, comms-manager | bun · Mastra · Drizzle |
Web apps gather into aumik-ui one PR per app (pattern proven on hospitality, aumik-ui#1): app under apps/<name>/, the Takeout framework hoisted to shared packages/, app overrides moved to the root package.json, seed bun.lock from the app's lockfile.
App inventory gathering into aumik-ui: hospitality (pilot, done) · assistants · alumni · food · dev · health · cleaning · astro.
aumik-dooh spans two monorepos
aumik-dooh is the DOOH (digital signage) product, split by runtime:
aumik-player→aumik-native— the on-screen player: installs on ReNative TV platforms (Tizen/webOS/Android TV/Fire TV); activate a screen → it plays scheduled videos/images. (Not a CMS.)dooh-portal→aumik-ui— the web management portal, two-sided: SSP (screen owners: activate/manage screens, playlists, scheduling, layouts, widgets) + DSP (advertisers: buy inventory, run campaigns). Mocked at the dooh prototype.dooh-landing— marketing site. Not anaumik-uiapp — it's a clickable lo-fi prototype inaumik-prototypes(per the ADLC prototype convention); rebuilt as a real app only if/when productized.
@aumik/portal — the shared self-service shell
Every Aumik product gets a customer self-service portal. Rather than per-product rebuilds, there's a generalized @aumik/portal package in aumik-ui: Better Auth customer accounts (phone-OTP) and self-service surfaces (starting with My Bookings). Each product mounts it scoped to its {resource}. Mocked in the scheduling prototype.
CI/CD
Per-repo hand-rolled CI is deferred — it lands as the reusable Aumik Quality Gate workflow_call (aumik-infra#11) + self-hosted Argos CI (aumik-infra#6), consumed by each monorepo. See Dev onboarding.
Booking & notifications
Two shared building blocks — platform foundations reused across every product, not one-offs. Tracking epic: aumik-infra#18. The booking/scheduling UX is mocked at the scheduling prototype.
Booking system — we build our own (no Cal.com)
Why not Cal.com: its API + API-key generation is Enterprise-gated even self-hosted (sales-quoted, ≥30-user minimum); only embed + webhooks are free. Not worth a paid EE license for one widget. So aumik-infra#5 (Cal.com) is closed and cal.* can be decommissioned.
Design
- Centralized in
aumik-agents— one booking service / DB / API, multi-tenant by{resource}, serving the chat widget, the agent (Level-3 auto-book via Mastra tools), and every product's@aumik/portal. packages/db(Drizzle, ownaumik_agentsDB):resources,availability_rules+availability_overrides,bookings,notifications,notification_prefs.packages/booking— pure service: availability (UTC-stored, TZ/DST-correct), a DB-level double-booking guard (EXCLUDE USING gistovertstzrange),.icsgeneration.apps/api— Hono REST alongside Mastra:GET /api/scheduling/{resource}/availability,POST …/book,PATCH …/bookings/{id}(reschedule),POST …/cancel.- No external calendar sync (no Google/Outlook two-way) — deliberate scope cut.
.icslinks only; revisit with Nylas/Cronofy only if customers demand it.
Get-it-right list: UTC + timezones/DST · DB-level conflict guard + idempotent book · reschedule/cancel state machine.
Notifications — engine is Novu (decided)
Channels: WhatsApp (Meta Cloud API) + SMS (gateway, default MSG91) are primary; email = Resend (domain aumik.co) for OTP + confirmations/fallback.
- One engine for email + SMS + WhatsApp across all products: built-in preferences, digests / retries / delivery logs, an in-app
<Inbox/>for@aumik/portal, and workflows-as-code (Novu Framework, fits Mastra). Adoption tracked inaumik-infra#19. - Integration:
comms-manageremits booking domain events (booking.confirmed,booking.reminder,booking.cancelled) → Novu workflows fan out by channel and honor per-user prefs. Novu's delay/digest handles 24h/2h reminders (no hand-rolled queue for notifications). - Self-host footprint on the box: API + Worker + WebSocket + Dashboard + MongoDB + Redis, co-tenant under Uncloud.
Infrastructure & deploy
One shared box runs everything. Know how it's laid out — and the rules that keep it alive — before you deploy.
The shared box
A single Hetzner server runs everything via Uncloud (lightweight Docker orchestration). All apps are co-tenants on it. Shared services, defined in aumik-infra/compose.yaml and deployed with uc deploy -y:
- Postgres 16 + pgvector — shared DB server; each app gets its own DB + role (
aumik_hospitality,aumik_food,aumik_law,infisical, …). - Redis 7 — shared cache + queue backbone (BullMQ jobs).
- Infisical — secret store (see Secrets).
- Caddy — reverse proxy + automatic TLS.
Other co-tenant services: Postiz (social scheduler), Radicale (CalDAV/CardDAV, caldav.aumik.co), prototypes (proto.aumik.co), and this handbook (docs.aumik.co). Cal.com is being decommissioned (see Booking).
Domains
*.aumik.co for any Aumik service (e.g. proto.aumik.co, docs.aumik.co). The cluster also has a *.uncld.dev address, but it's a volatile fallback that changes whenever the cluster is re-initialized — never hardcode it as a published URL.Hard rules — read before touching the box
uc machine init against the box. It re-initializes the cluster and wipes orchestration state (this has caused a production outage).🚫 Never
uc deploy --recreate on the shared infra compose. It corrupts the shared Postgres WAL for every app.⚠ App data lives in the shared Postgres. Confirm backup status (
aumik-hospitality#4) before any destructive operation.✅ App deploys are co-tenant: own image / services / subdomain / DBs; never touch shared state beyond adding your own DB.
Deploying an app
- Tier-B apps: the CI contract centers on a single orchestration command,
bun ops release(build → deploy → migrate), with secrets injected from Infisical. Reference:aumik-hospitality(live Tier-B + CI/CD reference). Copy its shape rather than inventing one. - Static sites (this handbook, the prototypes): an
nginx:alpineco-tenant serves a/srv/<name>dir; the repo is rsync'd up and the service redeployed via Uncloud. One-liner deploy lives in each repo (e.g../docs-site/deploy.shinaumik-infra). - Shared infra changes: from the
aumik-infrarepo, source the gitignored bootstrap.env, thenuc deploy -y(never--recreate) anduc caddy deployfor DNS + TLS.
Disaster recovery
- Cluster wiped, data survived (common case): run the infra recovery script — it validates secrets, aborts if the Postgres data dir is gone, reserves a domain, deploys without
--recreate, and health-checks. SeeRECOVERY.mdinaumik-infra. - Box totaled (no surviving data): blocked until DB backups land (
aumik-hospitality#4).
Secrets
All secrets live in Infisical (self-hosted on the box). Never hard-code them; never paste them into Slack or issues.
Pulling secrets
Use the aumik-ops-secrets-pull skill (wraps the Infisical CLI) to generate a local .env / .env.production for deploys:
aumik-ops-secrets-pull <project-slug> <env> [<out-path>]
It needs the machine-identity credentials (set as env vars); project IDs are cached locally.
What lives where
- The shared app-secrets project (Development env) holds shared keys — e.g. Resend (email; sending domain
aumik.co, verified), OpenRouter (LLM routing for widgets/agents), Postiz DB. Notification provider creds (Meta WhatsApp, SMS gateway) live here too once wired. - Bootstrap secrets that Infisical itself depends on can't live inside Infisical (chicken-and-egg). They live only in a gitignored
.envin theaumik-infrarepo, mirrored to 1Password + iCloud Keychain. See the infra repo for the exact set and rotation steps.
uc deploy by sourcing the infra .env into the shell (the pinned Uncloud version has no uc secret subcommand). Everything else is pulled from Infisical at deploy time.Brand / repo index
What each product is, its stack, and what stage it's at. Stage: live in production · active work in progress · scaffold early/greenfield.
Products
| Product | What it is | Stack | Stage |
|---|---|---|---|
aumik-hospitality | Real-estate / boutique zen-wellness brand + investor tools. CI/CD reference. | Takeout v2 | live |
aumik-astro | Premium self-service astrology portal (single-guru booking, AI-fuelled). Not a marketplace. · prototype ↗ | Vite·React·Shadcn → Takeout | active |
aumik-assistants | Consumer SaaS frontend for sector assistants (law → insurance/medical/home); brain is aumik-agents. | Takeout v2 | active |
aumik-alumni | Connects colleges with alumni; USP is official event photos / memories. · prototype ↗ | Tamagui·Supabase | active |
aumik-cleaning | Self-service marketplace to book cleaning services (customers ↔ providers). | Vite·React·Shadcn | active |
aumik-dev | Move businesses off Joomla/WordPress onto custom AI-enabled builds; GTM via preview sites. · prototype ↗ | Vite·React·Shadcn → Takeout | scaffold |
aumik-food | Vegan/veg tiffin-ordering (aumikfood.com): order flow, milk orders, admin. | Vite·React·Shadcn → Takeout | scaffold |
aumik-dooh | Digital out-of-home: screens + install, CMS (dooh-portal in aumik-ui), TV player (aumik-player in aumik-native). · prototype ↗ | ReNative + web | scaffold |
aumik-health | Clinical-research benchmarking SaaS; benchmark any health activity, public self-enroll. | Takeout | scaffold |
aumik-marketing | Cross-product campaign & ad-creative tracker (one issue per campaign). CRM product moved into aumik-ui. | docs / tracker | active |
Shared layers
| Layer | What it is | Stack | Stage |
|---|---|---|---|
aumik-agents | The brains — Mastra HTTP API (law/insurance/medical/home + shared) + booking service. Apps consume over HTTP. | Bun·Mastra·Drizzle | active |
aumik-ui | Web UI monorepo — all web apps + @aumik/widgets + @aumik/portal. | Bun·Tamagui·Turbo | active |
aumik-native | ReNative monorepo — first app is aumik-player (TV player). | yarn·ReNative | active |
aumik-skills | Shared Claude Code skills + ADLC commands. See Using aumik-skills. | Python | active |
aumik-infra | Shared infra compose (Postgres + Redis + Infisical) on Hetzner via Uncloud. Tooling, not a product. | Docker·Uncloud | live |
aumik-prototypes | Clickable lo-fi wireframes, one per product — the spec the dev team builds from. proto.aumik.co. | static HTML | live |
aumik-docs | This handbook. docs.aumik.co. | static HTML | live |
git remote -v) before pushing or running gh against a repo.Using the aumik-skills repo
Aumik's reusable Claude Code skills and ADLC commands — write them once here, consume them from any brand repo instead of re-implementing per repo.
Find your skills by role
Skills are named aumik-<role>-<task>. The prefix is organization, not access control — find your role's row and ignore the rest.
| Role | Prefix | Skills today |
|---|---|---|
| Dev | aumik-dev-* | aumik-dev-init-brand |
| Content | aumik-content-* | plan-script, scene-to-video, generate-book, song-to-video |
| PO | aumik-po-* | aumik-po-daily-standup |
| Ops | aumik-ops-* | aumik-ops-secrets-pull |
Layout
skills/<full-name>/SKILL.md— the skill itself (required).skills/<full-name>/references/*.md— optional contextual docs (linked from SKILL.md).skills/<full-name>/scripts/*.py— ported Python scripts..claude/commands/<full-name>.md— thin slash-command wrapper.aumik_skills/lib/— shared Python primitives (flux,brand_presets,book_lib,ffmpeg_helpers,secrets).
Consume it from a brand repo
pip install -e ../../aumik-skills
ln -s ../../aumik-skills/skills .claude/skills-shared
# symlink only your role's commands — keeps .claude/commands/ scoped:
ln -s ../../aumik-skills/.claude/commands/aumik-content-*.md .claude/commands/
Skills import from aumik_skills.lib, never from a sibling skill's scripts/.
When does a skill belong here?
- Cross-brand only — a skill lives here if ≥2 brands would benefit. Single-brand skills stay in that brand's own
.claude/skills/. - No brand-specific paths — take paths as arguments; don't assume a repo's layout.
- Defer to the brand's own
CLAUDE.mdfor operating rules — skills here are libraries, not policy.
Claude Code setup
Set up Claude Code the way the team runs it — the same plugins and memory layer, so skills and cross-session memory work out of the box.
1. Install Claude Code
Install the CLI and sign in (see the official Claude Code docs for your platform). Confirm it runs with claude in a repo.
2. Add the plugin marketplaces
Inside Claude Code, use the /plugin command to add the two marketplaces we use:
/plugin marketplace add anthropics/claude-plugins-official
/plugin marketplace add thedotmack/claude-mem
3. Install the plugins
/plugin install superpowers@claude-plugins-official
/plugin install claude-mem@thedotmack
/plugin install context7@claude-plugins-official
/plugin install code-review@claude-plugins-official
/plugin install claude-md-management@claude-plugins-official
- claude-mem — persistent cross-session memory. It captures observations as you work and surfaces relevant ones in later sessions, so Claude remembers prior decisions across the codebase.
- superpowers — the team's skills layer (brainstorming, systematic-debugging, TDD, writing-plans, and more). Claude invokes the right skill for the task automatically.
- context7 — fetches current library/framework docs on demand instead of relying on training data.
- code-review / claude-md-management — PR review and CLAUDE.md upkeep helpers.
4. Confirm settings
Your ~/.claude/settings.json should end up with the plugins enabled, e.g.:
{
"model": "opus[1m]",
"enabledPlugins": {
"superpowers@claude-plugins-official": true,
"claude-mem@thedotmack": true,
"context7@claude-plugins-official": true
},
"extraKnownMarketplaces": {
"thedotmack": { "source": { "source": "github", "repo": "thedotmack/claude-mem" } }
}
}
5. Per-repo: pull in shared skills
For Aumik repos, also wire in the shared skills as shown in Using aumik-skills — that gives you the aumik-<role>-* commands on top of the superpowers skills.
/plugin with no arguments to browse the current marketplace listings.