Files
cmux/skills/cmux-backend/references/effect-boundaries.md
T
Lawrence Chen 8c8c2bacae Compact CLAUDE.md and skills docs (#8990)
* Compact CLAUDE.md and skills docs

Cut ~2k lines of duplication without dropping actionable rules.

CLAUDE.md (267 -> 103): `reload.sh --tag` was explained four separate
times; now once. Dropped the Ghostty submodule and Release sections,
which restated the cmux-ghostty and cmux-release skills, and removed the
file:// deeplink block, which contradicted the rule that chat output
uses http://127.0.0.1:17320/<tag> and never a file:// URL. Pitfalls
compressed from paragraphs to one line each, pointing at the owning
skill.

skills/ (4849 -> 2819 across 20 skills): the dominant waste was SKILL.md
files restating their own references/ verbatim. Kept one canonical
statement with expansion in references/.

Three rules the root file carried had no skill that covered them, so
they moved into cmux-architecture rather than being lost: SPM package
group folders with check-workspace-package-groups.py, the
Package.resolved tracking policy, and "feature flag means a remote
PostHog runtime flag" via CmuxFeatureFlags. The cmuxTests pbxproj wiring
requirement was promoted from a reference file into cmux-testing, and
the shortcut policy moved into cmux-keyboard-shortcuts with its
duplicate removed from cmux-localization.

Stale references fixed:
- `cd cmuxd && zig build` referenced a directory with zero tracked
  files; the daemon is Go at daemon/remote/cmd/cmuxd-remote.
- Changelog page is web/app/[locale]/(landing)/docs/changelog/page.tsx,
  and configuration is under the same (landing) segment.
- Package CmuxSocketControl does not exist; the real one is
  CmuxControlSocket, cited twice as the exemplar to copy.
- Two rg commands in the localization audit were double-escaped and
  passed `--` as if it were a glob flag, so they matched nothing and
  silently passed the audit.

Left untouched: the auto-generated cmux-settings reference files, which
would drift from their generator.

* Dedupe release slash commands

release.md, release-local.md, and release-nightly.md each restated the
same version-bump and changelog procedure (450 -> 192 lines total).
release.md is now the canonical command doc holding the shared prep,
changelog guidelines, and contributor-credit format; the other two state
only their delta (local build-sign-upload.sh path, and no-PR direct-to-
main path with the homebrew-cmux submodule pointer commit).

Stale and incorrect instructions fixed:
- All three pointed at docs-site/content/docs/changelog.mdx. There is no
  docs-site/ in the repo; the changelog page renders from CHANGELOG.md.
- release.md said to hand-edit 'typically 4 occurrences' of
  MARKETING_VERSION in project.pbxproj. That leaves
  CURRENT_PROJECT_VERSION stale, which Sparkle requires to be monotonic
  and which release-pretag-guard.sh rejects. Unified on
  scripts/bump-version.sh, which bumps both.
- Documented build-sign-upload.sh --allow-overwrite, which matters
  because pushing a v* tag also fires release.yml, so a local upload can
  race CI for the same assets.

* Address review findings on submodule remotes and build links

- tagged-builds.md still told contributors to build chat links from the
  absolute .app path with a file:// URL, contradicting the rule in
  CLAUDE.md that chat links use http://127.0.0.1:17320/<tag>.
- cmux-ghostty said 'origin is upstream and manaflow is the fork' and
  pushed to a 'manaflow' remote. .gitmodules points every submodule at
  manaflow-ai/*, and no checkout has a 'manaflow' remote, so those
  commands would fail. Both the skill and submodule-safety.md now tell
  you to check git remote -v, and document adding an explicit 'upstream'
  remote for syncing from ghostty-org.
- submodule-safety.md verified ancestry against <remote>/main even when
  a feature branch was pushed. Now checks the branch actually pushed.
- release.md credited @lawrencechen; the account is @lawrencecchen.

Skipped, with reasons: the ~/.agents/skills vs ~/.codex/skills split in
cmux-customization is the documented convention (normal install vs
skills.sh install), matching cmux-diagnostics. Adding per-entry
attribution to the un-credited changelog example entry would contradict
the policy three lines above it, which exempts core-team work.
2026-07-26 23:16:39 -07:00

2.2 KiB

Effect Boundaries

Expands the backend TypeScript rules in ../SKILL.md for route handlers, services, and scripts.

Route handler shape

A handler is a shallow adapter: parse request input, select the Effect program, run it once at the boundary, translate domain errors to HTTP. Workflow sequencing, retries, provider calls, and database updates live outside the handler body. A handler that interleaves parsing, database writes, provider calls, and response construction makes retries and idempotency impossible to audit.

Reading one should immediately answer: what input the route accepts, which Effect program performs the workflow, which typed errors map to expected statuses, and which failures are unexpected defects.

Service shape

Use an Effect service when a workflow crosses an external boundary or has meaningful failure semantics: provider APIs, database reads/writes, auth and team lookup, payment or quota checks, retry and timeout policy, telemetry and usage recording, idempotency claims.

Model expected failures as typed domain errors named for the business failure. VmLimitExceeded, ProviderCapacityUnavailable, and IdempotencyConflict tell a caller more than a raw FetchError.

Dependency shape

Service dependencies are concrete capabilities declared as layer requirements: database client, provider client, auth/team service, clock or timeout policy, telemetry sink, idempotency repository. Not globals, broad ambient containers, or untyped option bags.

Plain TypeScript carve-out

Constants, schema declarations, config objects, frontend components, pure formatting helpers, and tiny route glue with no external effects stay plain TypeScript. Effect earns its place where explicit failure, dependency, retry, and cancellation semantics reduce real ambiguity.

Error mapping

When adding a route, check that invalid input maps to 400 or the existing validation status, auth and entitlement failures map to the existing auth/payment statuses, active-limit and quota failures are explicit, provider unavailability is distinguishable from a defect, and idempotency conflicts return a deterministic response. Never disguise an unexpected defect as an expected user error.