A baseline for Mercury repositories, written so an agent can be pointed at it:
"make this repo conform to our baseline." It defines the baseline. It does
not plan any repo's convergence: each repo is addressed in its own session,
which reads this page, compares the repo against it, and discusses the gaps
with Scott.
Where existing repos disagreed, Scott decided; those decisions are stated as
rules, not options. talaria is the reference implementation for lint, hooks, CI
shape and Dependabot; thoth is the reference for hgpacker deploy. The baseline
is expected to evolve: cases it does not yet cover, such as petasos's Lambda API
plus React ui/, the hg-packer build and the Dimensions sub-apps, are added
when a repo's own session runs into them.
This page is read from a local checkout of the wiki repo, not through the wiki
UI. Clone the wiki repo once, then start a session in the repo you want to
check and say:
Read
<path to your wiki clone>/repo_conventions.md, then compare this repo
to it. Report conforms / gap / not applicable for each item before changing
anything.
docs/baseline-exceptions.md, read it first; items it lists aredocs/baseline-exceptions.md (item and why, one entry each), so the nextAGENTS.md:.envrc or key files;Tiers: Required (every repo of that kind), If applicable (required
when the repo has the matching code), Optional.
AGENTS.md is the single source of truth.CLAUDE.md is a one-line file containing @AGENTS.md: not a symlinkCLAUDE.local.md counts as a Claude file andAGENTS.md content: one-paragraph description; common commands; architecturedocs/ rather than inliningAGENTS.md; skip the one-line CLAUDE.md.docs/ (Required)Never doc/. Rails stopped shipping doc/, and Codex and Claude both default
to docs/. New repos create docs/ only.
.envrc (direnv) holds local environment and must be gitignored.bin/setup check (preferred direction). bin/setup is kept currentbin/setup.envrc.sample as the interim alternative: committed, names and.envrc and stripping the.envrc (1.3) to do it..claude/settings.json is committed and denies Read(./.envrc), plus.powenv, config/**/*.key,config/credentials/*.key)..claude/settings.local.json, uncommitted.talaria-naming-conventions plugin from the private-agent-plugins.claude/settings.json.pre-commit, commit-msg,prepare-commit-msg..editorconfig at the root..worktreeinclude (Worktrunk allowlist for wt step copy-ignored) listing.bundle, vendor/bundle,node_modules, built assets. Comment each entry with why; a bare/* form where only files inside are ignored.Conventional Commits, enforced by commitlint in a commit-msg hook
(@commitlint/config-conventional; talaria adds the types debug and wip).
lefthook, config at .lefthook.yml (dotted). Hooks run only on staged files
({staged_files}), parallel: true, and mirror what CI lints so CI never
fails on something the hook would have caught.
A README.md. Content is not standardised here.
Settings live on GitHub, not in the checkout, so an agent verifies them with
gh api repos/mercuryanalytics/<repo> and .../rulesets (read-only).
main, with delete_branch_on_merge on.~DEFAULT_BRANCH requiring a pull request withdocs/baseline-exceptions.md.allowed_merge_methods is ["squash"],docs/baseline-exceptions.md.State at 2026-10-29: talaria, thoth and petasos have the ruleset (all three
still allow merge, squash and rebase). planctus, psychopomp and hg-packer have
no ruleset and no branch protection.
An advisory review bot, patterned on talaria (.github/workflows/):
claude-code-review.yml reviews each PR once, on opened,ready_for_review and reopened. Deliberately no synchronize: a/mercury-ci-review:ci-review with themercury-ci-review and mercury-coding-standards plugins from the privateprivate-agent-plugins marketplace (checked out with a read-only deploy key,AGENT_PLUGINS_DEPLOY_KEY), plus talaria-naming-conventions where the repoclaude.yml handles on-demand @claude mentions, for later review rounds.persist-credentials: false, CLAUDE_CODE_SUBPROCESS_ENV_SCRUB withCLAUDE_CODE_DISABLE_BACKGROUND_TASKS, a deliberate--allowedTools allowlist that omits anything able to run code or writeANTHROPIC_API_KEY secret and the workflow on the default branchState at 2026-10-29: talaria is the reference. thoth and petasos have both
workflows (shorter comments, petasos adds the public-repo gate). planctus,
psychopomp and hg-packer have neither.
.ruby-version: Ruby 3.3.4 (the hg-packer AMI runs Fullstaq Ruby3.3.4-jemalloc). .node-version: Node 22, pinned by major, where the.tool-versions is not part of the baseline;.tool-versions anyway, it must agree with them.ruby-version-file,node-version-file), not from restated literals. A hardcodedruby-version: / node-version: in a workflow is drift waiting to happen.assets:precompile.rubocop-rails, -rspec, -rspec_rails,-performance, -factory_bot; NewCops: enable. TargetRubyVersion tracks.ruby-version. A .rubocop_todo.yml is acceptable as a baseline for legacyAllCops/Exclude replaces the default list: restaterubocop-slim and slim-lint where Slim is used..prettierrc.json), ESLint flat--max-warnings 0 --report-unused-disable-directives,yarn typecheck) for TS code.lint-docs.yml.mercury-ruby-standards,mercury-typescript-standards, mercury-vitest-standards) are theBeyond 1.3's git-secrets and 1.5's commitlint, the pre-commit set is:
rubocop --force-exclusion, bin/check_gem_versions.sh,
bin/update_routes_comment (on config/routes.rb), plus the front-end
checks from 2.2 where they apply (ESLint, Prettier, stylelint, typecheck).
Copy the scripts from talaria.
One workflow per concern. Required: RSpec, lint-ruby, Brakeman;
if the repo has a front-end: lint-js and Vitest. Every workflow:
runs-on: ubuntu-24.04.push to main; pull_request withtypes: [opened, ready_for_review, synchronize]; workflow_dispatch onif: guard.concurrency: group ${{ github.workflow }}-${{ github.ref }},main.timeout-minutes (RSpec: 45).permissions:.paths: filters are fine, but main always runs the full suite, andMASTER_KEY, the AWS OIDC role) run in theintegration GitHub environment..github/actions/setup-rails-node, reading versions from the pin files.Optional: mirror-status.yml (republishes Actions check results as commit
statuses so /pulls/inbox sees them). It lists workflows by name, so any
new workflow must be added to its list. The Claude workflows are
deliberately excluded from it and must never be required checks.
The claude.yml and claude-code-review.yml workflows are optional and are
"extra", not official review. They do nothing until the workflow file is on
main.
.github/dependabot.yml: weekly, Mondays 06:00; grouped; ecosystems bundler,
npm (if a front-end), github-actions. Ignore only by
update-types: version-update:semver-* and never by versions:, which
would silence security advisories. See talaria's file for the commentary.
RSpec, FactoryBot, and parallel_tests
(rails parallel:create parallel:load_schema parallel:spec) once the suite
is large enough to matter. Front-end: Vitest. Visual regression (Playwright
plus lost-pixel) is optional.
Capistrano plus the capistrano-hgpacker gem, onto the hg-packer AMI.
The AMI provides the baseline (Ruby, Postgres client, Passenger and
passenger@.service, the deployer user, the /var/www/<app> skeleton,
credentials, logrotate and CloudWatch via first-boot rails-host-init); the
app declares only what it needs on top. Anything every app needs belongs in
hg-packer, not in the app.
Gemfile (development group): gem "capistrano-hgpacker", github: "mercuryanalytics/capistrano-hgpacker", tag: "v0.9.x", require: false.Capfile: require "capistrano/hgpacker" with the other plugin requires,capistrano/deploy. Remove require "capistrano/passenger" (thedeploy:restart; keeping both restarts it twice)deploy:restart actions.config/deploy.rb: rbenv_type :fullstaq, rbenv_ruby "3.3.4-jemalloc", and default_env path under/usr/lib/fullstaq-ruby/versions/3.3.4-jemalloc/bin.:required_packages, :hgpacker_host_files (files underconfig/hgpacker/), :hgpacker_services, :hgpacker_resque_memory.:web (Passenger), :resque (workers; only hosts that should runcap <stage> hgpacker:check reports drift between config, manifestDeploy workflow in hg-terraformworkflow_dispatch: app, environment, ref, hosts, action). A new app must beapp choice list. Spec:hg-terraform/docs/superpowers/specs/2026-10-22-central-deploy-workflow-design.md.capistrano-hgpacker;BRANCH for the stage's set :branch; build the stage's serverDEPLOY_HOSTS (comma-separated instance ids), defaulting to theHOSTS cannot do this, because itCapfile and config/deploy/*.rb.hg-packer/docs/rails-app-ami-migration.md (thoth). Link to it; do not copy.What a Rails app must provide, and expect, to be deployed and run on the
hg-packer AMI from hg-terraform. The app does not change hg-terraform; it hands
its infrastructure owner the list at the end.
What the app provides
/up (Rails' built-inconfig/deploy/staging.rb andconfig/deploy/production.rb; the Environment tag on a host is the stage.development group (BUNDLE_ONLY=development) against a frozen lockfile onCredentials=none.docs/baseline-exceptions.md, with how it is backed up and how it survives aName tag.How code ships
terraform apply. Inputs:staging or production), ref, optional hosts, andref must be on a remote branch of the app repo. Production deploys onlycap deploy:rollback and does not reverse migrations.hosts redeploys every running box tagged for the app andWhat the app asks its infrastructure owner for (an ask to the hg-terraform
session, not a change the app makes)
Application = the app's GitHub repository name (themercuryanalytics/<Application> and selects hosts by it) andEnvironment = staging or production, on the current hg-packer AMI.<app>/credentials/deploy-key; optionally <app>/credentials/rollbar-tokenrollbar/capistrano3; and the Rails key entry for eachapp choices, and its Ruby versionWorked examples in hg-terraform: talaria_services_staging.tf (public, behind
the staging ALB) and workbench_admin_*.tf (no ALB). Lifecycle and failure
modes: docs/rails-instance-lifecycle.md there.
Its own conventions (plan to a file, apply only with permission, commit and
push after an apply, secrets through asm-exec) are wired into that repo and
its CLAUDE.md; this document does not restate them. What other repos owe the
fleet is in 2.8.
ui/, CodeBuild): to be written when one of them is takendocs/baseline-exceptions.md.