Backend Code Review
langgenius/dify
Reviews backend code under api/ for concrete, reproducible defects, routes to rule packs for architecture, schema, repositories and SQLAlchemy, and ranks findings from P0 to P3.
A skill your agent uses when writing if (success) updateFetchKey(), an onRequestClose handler, or any refetch after a mutation; when a setting modal handles both create and update behind one…
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updates --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .claude/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .claude/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updatesType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updates --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .agents/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .agents/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updates --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .cursor/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .cursor/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/lablup/backend.ai-webui.git --path .claude/skills/relay-mutation-store-updates--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updates --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .gemini/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .gemini/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updatesInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .github/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .github/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install lablup/backend.ai-webui relay-mutation-store-updates --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/lablup/backend.ai-webui.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/relay-mutation-store-updates .opencode/skills/relay-mutation-store-updates && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "relay-mutation-store-updates" agent skill from https://github.com/lablup/backend.ai-webui/tree/main/.claude/skills/relay-mutation-store-updates into .opencode/skills/relay-mutation-store-updates/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "relay-mutation-store-updates", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
relay-mutation-store-updatesA skill your agent uses when writing if (success) updateFetchKey(), an onRequestClose handler, or any refetch after a mutation; when a setting modal handles both create and update behind one…
Relay Mutation Store Updates is an agent skill from lablup/backend.ai-webui. Use when writing if (success) updateFetchKey(), an onRequestClose handler, or any refetch after a mutation; when a setting modal handles both create and update behind one fragment prop; when choosing a mutation's response selection set; or when debugging "the list doesn't refresh after saving" / "why is it fetching twice". Covers when Relay patches the normalized store on its own, and when a refetch is genuinely the right answer.
Its SKILL.md is about 2.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Development. The repository describes itself as: Backend.AI Web UI for web / desktop app (Windows/Linux/macOS). Backend.AI Web UI provides a convenient environment for users, while allowing various commands to be executed… The licence is LGPL-3.0.
7 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit d6afd57. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are graphql and typescript).
From the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Relay Mutation Store Updates loads about 2.8k tokens when it runs. Until then it costs about 117 tokens; SKILL.md has 1,295 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from lablup/backend.ai-webui at commit d6afd57, republished under its LGPL-3.0 licence (© lablup). 1,295 words, ~2,793 tokens.
.claude/skills/relay-mutation-store-updates/SKILL.md (or your agent's skills folder).The rule this skill exists to enforce:
A refetch after an update mutation is a bug, not a refresh. Update mutations should return the changed fields so Relay patches the normalized store by
id. Refetch only when list membership changes.
This skill is the detailed treatment: how to tell the cases apart, and what to do in each.
onRequestClose={(success) => { if (success) updateFetchKey(); }}*Frgmt prop and branches create vs update insidemutation payloadAsk what changed, not did it succeed.
| What the mutation changed | What to do |
|---|---|
| Fields of an entity already in the store (update) | Select the changed fields on the returned node. Relay merges by id. No refetch. |
| Same, but a changed field is in the list's filter/orderBy | Still no refetch — patch the row. The row may stop matching the active filter, and that is accepted: the user should see the values they just edited on the row they touched, and every list carries a manual refresh (BAIFetchKeyButton) for re-evaluating the predicate. |
Same, but the payload returns only ok/msg (legacy) | Keep the refetch and comment why (§4). Nothing to merge. |
| List membership — a row added or removed (create/delete) | Refetch the list (§6). Don't patch the connection. |
| Server-derived fields you did not send (computed status, timestamps) | Select those too; refetch only if the server cannot return them (§7). |
An update mutation must return the entity and every field the calling UI
reads that the mutation could have changed. Relay merges the payload into the
normalized record by id, and every component holding that fragment
re-renders — with no extra network traffic.
# ❌ Payload carries no data, so the store goes stale
# and the caller is forced to requery the whole list.
modify_user(email: $email, props: $props) {
ok
msg
}# ✅ Spread the fragment the UI actually reads, so the selection set
# cannot drift out of sync with the component.
modify_user(email: $email, props: $props) {
ok
msg
user {
id
...YourListRow_user # ← the fragment your list row already renders
}
}If the consumer has no reusable fragment, hand-list every field the UI reads.
Relay keys normalized records by node id, but on types that implement Node
the compiler adds id to the network operation automatically — writing it
explicitly is a readability convention, not a correctness requirement. The
real gaps are always missing fields, not a missing id.
Dropping the refetch is only safe if the payload covers every field the UI reads that the mutation could change. A partial selection set gives you the worst of both: no refetch and no store update.
UserSettingModal demonstrates the trap. It sends groupIds and its
fragment reads projects { edges { node { id } } }, but the mutation
payload never selects projects — and the update path skips the refetch.
Changing a user's project membership succeeds on the server and leaves the UI
showing the old projects until a manual refresh.
Before removing a refetch, diff the two lists:
Anything in (1) that the mutation input can change and (2) omits is a stale-UI bug. Add it to the selection set — or keep the refetch and say why.
Most of this backend already returns the node; the frontend just isn't asking
for it. Before concluding a refetch is required, grep the payload type in
data/schema.graphql — if it has a node field, there is no excuse.
ok/msg mutations: keep the refetchA handful of mutations (ModifyAgent, ModifyImage, ModifyKeyPair,
ModifyScalingGroup, and the three Modify*ResourcePolicy) return only
ok/msg. There is nothing for Relay to merge, so keep the refetch and move
on — that is the accepted answer, not a gap to close. Leave a one-line
comment saying the payload carries no node.
Do not open a migration to their node-returning successors as part of an
unrelated change: it drags in backend version compatibility for little gain.
If you are already rewriting one of these call sites for another reason and a
successor exists (e.g. ModifyResourcePreset → UpdateResourcePresetPayload),
using it is a bonus, not a requirement.
Writing an updater by hand is also possible but rarely worth it. One
component does this today — react/src/components/AgentSettingModal.tsx:
commitModifyAgentSetting({
variables: { id: toLocalId(agent?.id ?? ""), props: { ... } },
updater: (store) => {
const agentRecord = store.get(agent?.id || "");
if (agentRecord) {
agentRecord.setValue(values.schedulable, "schedulable");
agentRecord.setValue(values.scaling_group, "scaling_group");
}
},
onCompleted(res, errors) { ... },
});Its call site (AgentNodeItems/AgentActionButtons.tsx) correspondingly does
not refetch — it only closes. Leave that one as it is.
If you do write an updater, cover only fields you sent and know the server
accepted verbatim. If the server transforms a value, you cannot guess it —
keep the refetch instead.
success honest — decide the refetch at the call siteonRequestClose(success: boolean) means the mutation succeeded. Pass it
truthfully.
Do not pass false after a successful update to suppress a refetch.
false already means "cancelled", so overloading it makes the two
indistinguishable to the caller — anything the caller later wants to do on
success (a toast, clearing a selection, closing a drawer) silently stops
firing after updates. UserSettingModal currently does this; it is a bug to
copy from, not a pattern.
The fragment prop is the discriminator. A setting modal that handles both
paths takes a nullable *Frgmt — null means create, non-null means update.
The caller passes that prop, so it can branch on it with no signature change:
if (success && entityFrgmt === null) refetch(). Create adds a row the
connection doesn't know about; update has already been patched into the store.
One instance serving both paths:
<ResourcePresetSettingModal
resourcePresetFrgmt={editingResourcePreset}
open={!!editingResourcePreset || isCreating}
onRequestClose={(success) => {
// read the fragment BEFORE the resets below; the handler closes over the
// render-time value, so check first and reset after.
if (success && !editingResourcePreset) {
startRefetchTransition(() => updateResourcePresetsFetchKey());
}
setEditingResourcePreset(null);
setIsCreating(false);
}}
/>When the caller renders separate instances for create and edit — as
AdminUserManagement does with userSettingFrgmt={selectedUser} and
={null} — the branch collapses. Its edit path still keeps the refetch,
for the §2 reason: the status-toggle payload
returns only user { id }, so the changed fields never come back and there
is nothing to patch. Fill the payload first if you want to drop that one.
If a caller genuinely cannot know, enrich the result rather than lying about
success — ContainerRegistryEditorModal already passes
onOk('create' | 'modify').
Refetch the list. Don't patch the connection.
Connection directives (@appendEdge, @deleteRecord) look like the tidy
answer, but they break under pagination: appending to a page-sized connection
pushes rows past the cursor boundary, so the client's idea of the list drifts
from the server's. Add sorting and filtering — where the new row's position is
decided server-side — and a client-side insert is simply guessing.
One component uses @appendEdge today
(packages/backend.ai-ui/src/components/fragments/BAIImportArtifactModal.tsx).
Treat it as an exception that predates this rule, not a pattern to copy.
Create and delete are settled by §6. An update may also legitimately refetch when:
Leave a one-line reason in these cases. After an update, an unexplained refetch reads as the anti-pattern.
There is none — this skill and code review are the only guardrail, across ~149
updateFetchKey() call sites in react/src. A lint rule was considered and
deliberately left out of scope (FR-3372). If that decision is revisited, the
landing spot already exists: react/eslint.config.js uses no-restricted-syntax
with an AST selector for the CSP <style> ban, and the
onRequestClose={(success) => { if (success) updateFetchKey(); }} shape is
matchable the same way.
if (success) updateFetchKey() where the mutation was an updatedata/schema.graphql) before concluding a refetch is requiredok/msg-only mutation → refetch kept, with a comment saying whysuccess is passed truthfully; the refetch decision lives at the call site@appendEdge/@deleteRecord added.specs/FR-3372-refetch-after-mutation/spec.md — the remediation spec this skill distills© lablup, LGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/relay-mutation-store-updates of lablup/backend.ai-webui.
Open the folder on GitHubat commit d6afd57
Relay Mutation Store Updates next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Relay Mutation Store Updates this skilllablup/backend.ai-webui | 133 | — | ~2.8k | Automated safety check: Pass | LGPL-3.0 | |
| Backend Code Reviewlanggenius/dify | 158k | — | ~676 | Automated safety check: Pass | Custom licence | |
| Native Data FetchingCherryHQ/cherry-studio-app | 4k | 6 repos | ~2.9k | Automated safety check: Notes | MIT | |
| Twenty App Entity Developmenttwentyhq/twenty | 58k | — | ~1.8k | Automated safety check: Pass | Custom licence | |
| Go Pedantrychromedp/chromedp | 13k | — | ~3.7k | Automated safety check: Pass | MIT | |
| Gumroad Prod Consoleantiwork/gumroad | 9.8k | — | ~2.9k | Automated safety check: Notes | MIT |
langgenius/dify
Reviews backend code under api/ for concrete, reproducible defects, routes to rule packs for architecture, schema, repositories and SQLAlchemy, and ranks findings from P0 to P3.
CherryHQ/cherry-studio-app
A skill your agent uses when implementing or debugging ANY network request, API call, or data fetching.
twentyhq/twenty
Guides changes to an existing Twenty app: adding or editing objects, layouts, logic functions and front components, with a plan stated before multi-entity edits.
chromedp/chromedp
This skill should be used when the user is writing Go code and needs guidance on Go-specific pedantry: error wrapping with fmt.Errorf and %w, interface design (accept interfaces return structs)…
antiwork/gumroad
Execute read-only Ruby/Rails commands against Gumroad's production database for debugging and investigation.
langbot-app/LangBot
Guides building, debugging and testing LangBot plugins: components, SDK calls, README and locale rules, SDK pitfalls and WebSocket-based testing.
lablup/backend.ai-webui
Mint a walkthrough for the PR this session just implemented: a set of numbered stops a reviewer opens in the live dev server, each one marking an element on screen with what changed and what to check.
lablup/backend.ai-webui
A skill your agent uses whenever the user mentions docs, the manual, documentation, terminology, translations, or screenshots — including indirect mentions like "이 PR 문서 영향 봐줘", "문서 점검", "용어 통일"…
lablup/backend.ai-webui
Expert guide for Backend.AI distributed computing platform. An agent skill from lablup/backend.ai-webui.
lablup/backend.ai-webui
Start the project's development server (pnpm dev for backend.ai-webui; discovered from README/package.json elsewhere), deriving the header color, app name, default backend endpoint and login…
lablup/backend.ai-webui
Record Playwright e2e tests as one GIF per test case (video → ffmpeg palette GIF) and return a markdown table for a PR description.
lablup/backend.ai-webui
Post a Korean release risk digest to a Microsoft Teams thread, grouped by risk category.
Categories
A skill your agent uses when writing if (success) updateFetchKey(), an onRequestClose handler, or any refetch after a mutation; when a setting modal handles both create and update behind one…. ai-webui. Use when writing if (success) updateFetchKey(), an onRequestClose handler, or any refetch after a mutation; when a setting modal handles both create and update behind one fragment prop; when choosing a mutation's response selection set; or when debugging "the list doesn't refresh after saving" / "why is it fetching twice".
Relay Mutation Store Updates fits situations like: writing if (success) updateFetchKey(); an onRequestClose handler; any refetch after a mutation; A setting modal handles both create and update behind one fragment prop.
Run `npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a claude-code`. Or copy the skill folder (.claude/skills/relay-mutation-store-updates in lablup/backend.ai-webui) into .claude/skills/relay-mutation-store-updates in your project. Claude Code loads it when a task matches its description.
Run `npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a codex`. Or copy the skill folder (.claude/skills/relay-mutation-store-updates in lablup/backend.ai-webui) into .agents/skills/relay-mutation-store-updates in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add lablup/backend.ai-webui --skill relay-mutation-store-updates -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/relay-mutation-store-updates, .gemini/skills/relay-mutation-store-updates, .github/skills/relay-mutation-store-updates and .opencode/skills/relay-mutation-store-updates in your project.
SKILL.md names no scripts, command-line tools or credentials: Relay Mutation Store Updates is instructions for the agent only.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Relay Mutation Store Updates is published under the LGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.8k tokens (SKILL.md is roughly 11k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Relay Mutation Store Updates: Backend Code Review (langgenius/dify, 158k stars), Native Data Fetching (CherryHQ/cherry-studio-app, 4k stars), Twenty App Entity Development (twentyhq/twenty, 58k stars) and Go Pedantry (chromedp/chromedp, 13k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
lablup (a GitHub organization) maintains it in lablup/backend.ai-webui, which has 133 GitHub stars. The repository holds 13 skills in this directory. The repository was last updated on October 8, 2026.
Source: lablup/backend.ai-webui on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.