To run and test, see README.md.
Two habits that keep task-focused changes from scarring the rest of the repo:
- Do not add AI authorship attribution to commits or pull requests. Omit
Co-authored-bytrailers for Codex, Claude, or other AI tools, and omit tool-generated attribution footers such asGenerated with Codex. Preserve legitimate human coauthors. CI rejects AI coauthor trailers on new PR commits; do not rewrite existing repository history to remove attribution. - Fix every instance, not just the reported one. When you find a bug or a pattern
worth changing, grep the whole repo (
src/,plugins/,test/,scripts/) for the same pattern and fix all of it in the same change. One autocorrected call site with five untouched siblings is a regression waiting to be rediscovered. - Fixes should make the system simpler, not more complex. Prefer removing or consolidating code over adding a new layer, flag, or special case. If a fix grows the system's surface area, look for the version that shrinks it.
- Never leave comments in the repo. The standard is zero comments: no explanatory comments or docblocks, TODO/FIXME notes, lint/type suppression directives, or commented-out code. Express intent through names, structure, and tests; put rationale in commit messages or PR descriptions. Interpreter shebangs are executable directives, not comments.
- Solve at the layer all paths flow through. Before patching a call site, ask
whether the fix belongs in the shared helper, the store interface, or the base
module instead. Check for an existing helper before writing a new one-liner.
The helper homes:
src/util/errors.ts(errMessage/swallow),src/util/async.ts(sleep, createKeyedQueue),src/util/sweeper.ts(periodic loops),src/sandbox/process-poll.ts(process polling/liveness),src/memory/notebook.ts(memory line grammar). Plugins are separate packages and keep their own local copies rather than importing core code — the one exception is the sharedplugins/chassispackage (the sanctioned home for the plugin↔core plumbing: source-auth signer, signed core-client, node:http helpers, error helpers, CORE_* env), imported by relative path and never importing core. The bar cuts both ways: don't manufacture an abstraction for a pattern with one caller. - Never merge to
mainwithout a fresh-context pass that tries to break the change. Not a blessing — hunt for the bug, the missed edge case, the unstated assumption, the thing that regresses. Always dispatch/code-reviewor an independent review agent that did not watch you write the change: the context that produced a diff already believes it is correct, and that belief is the bias review exists to defeat. Never self-review in the authoring context, however small the diff; a green CI run is not review either. What scales with risk is how deep the reviewer goes — a change with a narrow blast radius warrants one reviewer at modest effort scoped to the diff, while core control flow, auth and credentials, data loss or migrations, concurrency and retry logic, spend, public API contracts, the shared helpers above that every path flows through, or a diff too large to hold in your head warrant high effort and several reviewers with distinct lenses. Judge blast radius by checking callers, not by counting files — a one-line edit to a helper with fifty importers is not a small change. The reviewer, not the author, has the last word on depth: a modest pass that spots risk it wasn't scoped for escalates on its own initiative rather than staying in its lane. Resolve what they find before merging. - Verify locally with the affected tests, not the whole suite. Run the tests covering what you changed plus typecheck and lint, then push and let CI be the full gate — CI shards the suite across parallel runners, and reproducing that serially costs several times the wall clock for the same signal. Judge "affected" by callers rather than by diff size, for the same reason as above; run everything locally when you can't tell what a change reaches.
- Verify non-trivial behavior changes in a live dev instance before opening a PR.
When a change is substantial enough that unit tests alone won't prove it works
end-to-end — new or changed agent behavior, or anything touching the Slack/web
surfaces, orchestrator, directory, or cron flows — boot this worktree with the
/dev-instanceskill and exercise it through a browser against the configured Slack development workspace before opening a PR. Do this Slack QA in Firefox, never the Slack Mac app, and don't ask permission first — do it on your own; don't wait to be asked. Skip it for trivial refactors, docs, config, or pure-logic changes already covered by tests. - Keep screenshots out of Git and app assets. Never commit screenshots or create a tracked screenshots directory, including under docs or QA. Capture review images in a temporary directory outside the checkout or an ignored local output directory, and attach them to the PR or host them externally. Do not bundle review screenshots into the app. Only actual product assets, such as icons and instructional media, belong in the app bundle.
- Demo every front-end change in the PR. Anything an operator or user sees rendered — admin/web/portal UI, Slack surfaces, emails — ships with a way for a reviewer to see the result without booting it. Prefer a link to a live demo app (e.g. the built UI served against a small mock API, published internally) so the reviewer can click around the real thing; note in the PR what's mocked. Fall back to screenshots only when a live demo isn't practical (e.g. Slack surfaces, emails), and then show the after state (before/after for changes to something that existed), rendered against realistic data. Attach or externally host these screenshots; never commit them to satisfy this requirement.
Before acting, run git remote -v and inspect the checkout. origin pointing at
yc-software/qm identifies upstream. Another origin alone does not identify a source
fork: a package deployment has its own qm.config.jsonc and pinned @yc-software/qm
dependency, while a source fork carries the QM source tree and upstream ancestry.
Package deployments customize config, tools, skills, and services without copying core.
Source forks may modify core freely, including runtime, plugins, CLI, docs, and CI;
contributing those changes upstream is optional. Keep private deployment material under
deploy/layers/<org>/ in private source forks or in a separate private deployment
repository for public source checkouts. Secrets never enter Git. The README section
"Customize your instance" documents both paths and explicit source builds.
Create private source forks as standalone repositories outside GitHub's fork network.
Seed only main and set the default branch explicitly; never use git push --mirror.
Use update-qm to merge source updates without rebasing published history or discarding
intentional local changes. Land source-sync PRs without squashing or rebasing away their
upstream ancestry. Package deployments update their dependency instead.
In downstream repositories, pass --repo to every gh command so the upstream remote
cannot redirect an operation. When contributing from private work, use upstream-pr
to prepare a clean branch and scrub outgoing content and history. Never reference an
upstream issue or PR by number in private repository PRs, issues, comments, or commit
messages: GitHub cross-references can disclose their existence and titles upstream.
Name upstream work in plain words instead.
A recurring mistake: stashing state the system later relies on in process memory. The
core runs blue-green and multi-instance — an in-memory Map or ring buffer is
per-instance and wiped by every deploy. Anything an operator or the system reads back
later (audit, logs, resolved config, queued or in-flight work) must live in a durable
store, never RAM alone. RAM-only is fine only as a cache in front of a durable store, or
for genuinely disposable, re-derivable state. If you're adding a log, audit, queue, or
resolved config, back it with Postgres; the spec's data-model & durability section tracks the gaps.
CLAUDE.mdis a symlink toAGENTS.md, so every tool (Claude Code, Codex, Cursor, …) reads the same guidance from this one file. If a tool-specific deviation ever becomes necessary, replace the symlink with a real file in the commit that introduces the deviation.