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:

TrackWhat they do
DevScaffold, build, deploy, and migrate Aumik apps.
ContentBooks, marketing video, and song videos (Tirhut Press, Balmukund).
POPortfolio + team rituals — standups, milestones, access.
OpsDeploy-time plumbing — secrets, infra.
Where this lives: this handbook is the team-facing view. Cross-cutting business decisions, confidential client/partner material, and per-person notes are not here — they live in the operator's private control plane.

Dev onboarding

Getting a new dev or intern productive: access, the lay of the land, and how work actually moves.

1. Get access

  1. Send your GitHub handle to your PO — you'll be added to the aumik-labs org and granted collaborator access on the repos you're assigned to.
  2. You'll be invited to Slack#aumik-dev is the main dev channel, #standup is where the async daily standup runs.
  3. 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:

  1. Milestones / tracking stories live in aumik-infra, assigned to Aniket.
  2. 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.
  3. 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.

Quality Gate. Merging to prod requires 1 approval from Aniket + 1 of Omkar / Achal / Deepak, plus lint/typecheck/unit/security + Argos visual regression on affected apps. (Reusable 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-dev with 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:

LayerTool
App frameworkOne (Vite-based RN + web, replaces Next.js + Expo Router)
UITamagui
Realtime syncZero (Rocicorp)
AuthBetter Auth
ORMDrizzle
Package managerBun (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 bun workspace:*).
  • 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.

Why Uncloud is the default: it's the officially-stable Takeout deploy path (SST/AWS is upstream "work in progress"), its cost shape (~$5–20/mo/VPS shared) beats ~$140–300/mo/app on AWS, and Docker + Caddy is a far smaller ops surface than ECS + Aurora + Zero services + Lambda + VPC.

Monorepos — what goes where

Three runtime-split monorepos. Pick by runtime, not by product.

MonorepoRuntimeHoldsToolchain
aumik-uiWeb (Tamagui/One)All web UI apps + shared @aumik/* packages (widgets, portal, tsconfig, eslint-config)bun · Tamagui · Turbo
aumik-nativeReNative (TV/mobile)Cross-platform/TV apps — first app aumik-playeryarn · Metro · Turbo
aumik-agentsBun · MastraShared AI backend: agents, tools, the booking service, comms-managerbun · 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-playeraumik-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-portalaumik-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 an aumik-ui app — it's a clickable lo-fi prototype in aumik-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, own aumik_agents DB): 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 gist over tstzrange), .ics generation.
  • 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. .ics links 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 in aumik-infra#19.
  • Integration: comms-manager emits 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.
Lead-time warning: start the WhatsApp Business + message-template approval and SMS gateway accounts on day 1 — they have external approval lead time that will otherwise block launch.

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

Rule: always use *.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

🚫 Never run 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:alpine co-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.sh in aumik-infra).
  • Shared infra changes: from the aumik-infra repo, source the gitignored bootstrap .env, then uc deploy -y (never --recreate) and uc caddy deploy for 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. See RECOVERY.md in aumik-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 .env in the aumik-infra repo, mirrored to 1Password + iCloud Keychain. See the infra repo for the exact set and rotation steps.
Sourcing for deploys: bootstrap secrets are fed to 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

ProductWhat it isStackStage
aumik-hospitalityReal-estate / boutique zen-wellness brand + investor tools. CI/CD reference.Takeout v2live
aumik-astroPremium self-service astrology portal (single-guru booking, AI-fuelled). Not a marketplace. · prototype ↗Vite·React·Shadcn → Takeoutactive
aumik-assistantsConsumer SaaS frontend for sector assistants (law → insurance/medical/home); brain is aumik-agents.Takeout v2active
aumik-alumniConnects colleges with alumni; USP is official event photos / memories. · prototype ↗Tamagui·Supabaseactive
aumik-cleaningSelf-service marketplace to book cleaning services (customers ↔ providers).Vite·React·Shadcnactive
aumik-devMove businesses off Joomla/WordPress onto custom AI-enabled builds; GTM via preview sites. · prototype ↗Vite·React·Shadcn → Takeoutscaffold
aumik-foodVegan/veg tiffin-ordering (aumikfood.com): order flow, milk orders, admin.Vite·React·Shadcn → Takeoutscaffold
aumik-doohDigital out-of-home: screens + install, CMS (dooh-portal in aumik-ui), TV player (aumik-player in aumik-native). · prototype ↗ReNative + webscaffold
aumik-healthClinical-research benchmarking SaaS; benchmark any health activity, public self-enroll.Takeoutscaffold
aumik-marketingCross-product campaign & ad-creative tracker (one issue per campaign). CRM product moved into aumik-ui.docs / trackeractive

Shared layers

LayerWhat it isStackStage
aumik-agentsThe brains — Mastra HTTP API (law/insurance/medical/home + shared) + booking service. Apps consume over HTTP.Bun·Mastra·Drizzleactive
aumik-uiWeb UI monorepo — all web apps + @aumik/widgets + @aumik/portal.Bun·Tamagui·Turboactive
aumik-nativeReNative monorepo — first app is aumik-player (TV player).yarn·ReNativeactive
aumik-skillsShared Claude Code skills + ADLC commands. See Using aumik-skills.Pythonactive
aumik-infraShared infra compose (Postgres + Redis + Infisical) on Hetzner via Uncloud. Tooling, not a product.Docker·Uncloudlive
aumik-prototypesClickable lo-fi wireframes, one per product — the spec the dev team builds from. proto.aumik.co.static HTMLlive
aumik-docsThis handbook. docs.aumik.co.static HTMLlive
Before you push: a few repos were renamed on GitHub and some local clones / deploy configs still point at old slugs. Verify the remote (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.

RolePrefixSkills today
Devaumik-dev-*aumik-dev-init-brand
Contentaumik-content-*plan-script, scene-to-video, generate-book, song-to-video
POaumik-po-*aumik-po-daily-standup
Opsaumik-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.md for 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.

Verify before relying on exact versions: plugin versions move (this team is on superpowers v6.x and claude-mem v13.x). If a command name has changed, run /plugin with no arguments to browse the current marketplace listings.