SLOPSHOPPER

qsm-essentials

The method every session can draw on: how to look at work before building it, the method skills for design, testing, debugging, refactoring, modelling…

newrowsagents
A shopper browsing a rack in a slop shop
README

qsm-essentials

The core method for an agent working beside a senior programmer: ten skills and four agents for design, testing, debugging, delegation and more.

Why it exists

Without a shared method, every session relearns how this person works: it builds before it understands, settles design by default, forgets what an earlier session decided, and either does everything itself or hands everything away. qsm-essentials is that method: the thinking of a senior programmer about a real problem, written as skills and bounded agents an agent applies, not as a summary a plain model already knows. It takes the stance that a skill earns its place only when the agent works measurably better with it than without. It refuses to hold anything specific to a language, a framework, a project or a machine, and refuses to restate what a plain model does well. When the harness ships this method itself, or a plain model matches it, this plugin has no reason to exist.

What you get

KindNameWhat it does
SkilldebuggingFinds the root cause of a bug or a flaky test before any fix is tried
Skilldistributed-systemsService boundaries, sync or async, data ownership, failure across a network
Skilldomain-modelingEntities, values, aggregates and where a business rule lives
SkillrefactoringChanges structure without changing behaviour, in steps that each stay working
Skillrun-and-verifyStarts the project and proves a change works before anyone says it does
Skillsoftware-architecturePicks an architecture style, weighs trade-offs, records the decision
Skillsoftware-designCuts modules, shapes interfaces and types, decides where complexity lives
Skillsoftware-testingDecides if a change needs a test and picks the cheapest one that runs the real path
SkillsubagentsWrites the task for an agent, splits work, accepts what comes back
SkillwritingCommit messages, tickets, review replies, READMEs, error messages
AgentresearcherAnswers where, what and how over a code tree, with file and line citations
AgentrunnerRuns one noisy command, keeps the log, returns a short briefing
AgentimplementerBuilds one bounded task in its own worktree and proves it end to end
Agentweb-researchAnswers one question from the web in at most five rounds, with sources

Install

claude plugin install qsm-essentials@qsm-marketplace

Install adds the skills and agents only. It has no binary and no dependency.

The web-research agent is the default for the web-research role. A plug-in that ships its own agent of that name replaces it, and the role is that agent's; the core one is the one to use when no plug-in does.

Use

Skills fire on the kind of ask, so there is nothing to call.

  • ask: "why does this test fail only on CI?" loads debugging.
  • ask: "should this be its own service?" loads distributed-systems.
  • ask: "write the commit message for this" loads writing.
  • ask: "hand these three tasks to agents" loads subagents, which then picks implementer, researcher or runner for each.

Caveats

  • No language idioms and no project or machine facts. Those live in other plug-ins.
  • The core names no other plug-in. A tool the skills mention, such as a code index or web search, is used by role when one is installed.
  • Every agent must name its model: a hook refuses an Agent call, a workflow agent or a plugin's spawn without one (a fork excepted), puts the tier in front of the description ([sonnet] researcher: …), and draws the tier in colour before the Agent row in the transcript.
Source 2 files
hooks/register.tsx 41 lines
1// qsm-essentials' function-hooks module: every agent names its model, and the transcript shows it.
2// The rules are lib/agent-model.ts; the hooks only refuse, tag and draw.
3import type { On } from "claude-code";
4import { NO_MODEL, TIER_COLOR, tagged, tierOf } from "../lib/agent-model.ts";
5
6export function register(on: On): void {
7  on("agent.spawn", (_$, e, next) => {
8    if (e.fork) {
9      return next(e);
10    }
11    if (e.model === undefined || e.model === "") {
12      return { deny: NO_MODEL };
13    }
14    // A workflow agent's content cannot be rewritten; the engine would log the attempt.
15    return e.workflow === undefined
16      ? next({ ...e, description: tagged(e.description, e.model) })
17      : next(e);
18  });
19
20  on("ui.render", { component: "ToolUse" }, async ($, e, next) => {
21    const { input } = e.props;
22    const model =
23      e.props.tool === "Agent" && typeof input === "object" && input !== null && "model" in input
24        ? input.model
25        : undefined;
26    if (typeof model !== "string") {
27      return next(e);
28    }
29    const tier = tierOf(model);
30    const { Box, Text } = $.ui.resolve(e);
31    return (
32      <Box flexDirection="row">
33        <Text color={TIER_COLOR[tier] ?? "gray"} bold>
34          {tier}{" "}
35        </Text>
36        {await next(e)}
37      </Box>
38    );
39  });
40}
41
lib/agent-model.ts 25 lines
1// Every agent names its model: the tier of a model alias or id, the refusal for a spawn that names
2// none, and the colour the transcript draws each tier in.
3
4const TIERS = ["haiku", "sonnet", "opus", "fable"] as const;
5
6export const TIER_COLOR: Readonly<Record<string, string>> = {
7  haiku: "green",
8  sonnet: "cyan",
9  opus: "magenta",
10  fable: "yellow",
11};
12
13export const NO_MODEL =
14  "Name the model on every agent (haiku, sonnet, opus or fable): an agent left without one inherits the session's model.";
15
16/** The tier word of a model alias or id (`claude-sonnet-5-5` is sonnet), else the model itself. */
17export function tierOf(model: string): string {
18  return TIERS.find((tier) => model.includes(tier)) ?? model;
19}
20
21/** The description with the tier in front, unless it already opens with a bracket. */
22export function tagged(description: string, model: string): string {
23  return description.startsWith("[") ? description : `[${tierOf(model)}] ${description}`;
24}
25