Agent loops, tool calling, prompt and context assembly, agent SDKs and coding assistants.
774 instructions from 49 repositories. Last updated 2026-07-29.
Standard: at every trust boundary, enforce security invariants in a way that cannot be skipped by flags, parsing edge cases, alternate code paths, or serialization differences.
Checklist (apply consistently): 1) Feature flags must not become bypass switches
2) Validate identifiers and map them safely to filesystem/network usage
.., control chars).Example (route boundary):
function assertSessionId(raw: unknown): string {
if (typeof raw !== 'string') throw new Error('invalid');
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(raw))
throw new Error('invalid');
return raw;
}
3) Handle untrusted filesystem objects safely (symlinks/TOCTOU)
lstat/stat followed by readFile where the path can be swapped.open() with O_NOFOLLOW (and reject non-regular via fstat) and enforce a size cap before reading.4) Sanitize all outputs on every path (not just the happy path)
Example (cancel path must sanitize like append):
await finalize(segmentId,
sanitizeStreamingImageMarkers(record.content),
'Cancelled',
false,
);
5) Authorization/auth token propagation must be end-to-end
6) Confidentiality: treat platform “internal” flags as security labels
7) Parsing/regex guards must be robust to escape and grammar edge cases
8) Enforce sender-policy and consistent untrusted-data framing before aggregation
text consistently across lanes and first-contact paths.9) Don’t trust carriers written by the audited execution
This standard is meant to be a practical code-review rubric: when you see “allow/skip/early return/regex parse/check-then-use”, require that the security invariant still holds and that untrusted data cannot reach sinks (filesystem paths, network endpoints, subprocess argv, UI/LLM text, or public replies) without the corresponding validation/sanitization/authorization guarantees.
When code adds/changes behavior (UI logic, URL rewriting, state-merge rules, keyboard/pointer guards, or error-recovery flows), ensure tests cover (1) the behavior itself (not just indirectly), (2) the negative guard cases that prevent regressions, and (3) the full interaction path users trigger.
Practical rules: 1) Lock shipped behavior with direct tests
2) Add negative tests for safety guards
pointerId, event.detail guard, tap-vs-hold mode).3) For UI, test “click/trigger → menu/content/action”
4) Keep test selectors unique and stable
data-testid values within the same query scope; use distinct ids for container vs. inner components to prevent E2E query cardinality failures.Example (Vitest):
import { describe, it, expect, vi } from 'vitest';
// Ensure both guard paths and the interaction path are tested.
describe('Pointer guard + action', () => {
it('ignores non-primary pointer in hold mode', () => {
// render component with hold mode; use user-event/pointer helper
// pointer(button, 'pointerdown', pointerId=1, mouseButton=2)
// expect(start).not.toHaveBeenCalled();
expect(true).toBe(true);
});
it('opens overflow menu and executes host action', async () => {
const onShare = vi.fn();
// render PaneHeaderActions with a host action
// force collapse widths
// click overflow trigger
// expect(menu items include 'Share')
// click menu item -> expect(onShare).toHaveBeenCalledTimes(1)
expect(onShare).toHaveBeenCalledTimes(0);
});
});
Adopting this standard prevents the recurring issues seen across discussions: untested shipped branches, missing guard negatives, interaction paths that stop short of what users do, and fragile test selector collisions.
Make workflow/test suites “branch-complete and predicate-exact”: every reachable case arm and every required gating condition must be exercised and asserted, with environment-correct shims/guards.
Apply this standard:
1) Table-driven mapping tests must include every reachable branch (don’t rely on bijection checks only over the listed subset). If a case arm exists in the implementation, it must appear in the ARMS/fixtures list.
2) Ensure mocks/fixtures actually enter the new code path. If the PR adds an if/mapping branch, add a test where that branch evaluates true (or explicitly covers each comparison outcome).
3) Assert the full predicate, not just a prefix. If the gate is A && B && C, your test should check that the produced script/body contains all three conditions (missing one enables false-green).
4) Add OS/CI guards for end-to-end tests that rely on POSIX behavior or GNU tools. Use itOnUnix or darwin-only shims for sed -i and avoid shebang/shim issues on Windows merge-queue.
5) For timing/loop bugs, construct inputs so the code reaches the failing region (e.g., ensure a retry loop re-enters after the deadline check).
Example patterns:
case arms in ARMS
const ARMS = [
// ...existing arms...
[{ VERDICT: 'infra-error' }, 'infra-error (crash, OOM, or unwritable results)', '基础设施故障(崩溃、OOM 或结果不可写)'],
[{ VERDICT: '' }, 'unknown', '未知'],
];
expect(seenZh.size).toBe(ARMS.length);
const itOnUnix = process.platform === 'win32' ? it.skip : it;
itOnUnix('fails on real critical vulnerability', () => {
// end-to-end with npm shim
});
// gate must require ASSERT_LINE as well as REPORT
expect(publishStep).toMatch(/\[ "\$\{VERDICT:-\}" = 'pass' \] && \[ -n "\$REPORT" \] && \[ -n "\$ASSERT_LINE" \]/);
If you follow these rules, regressions like “missing untested arms,” “new branch never executed,” “gate predicate weakened,” and “POSIX-only shims failing on Windows/macOS” are far less likely to slip through CI.
Adopt a rule that comments/JSDoc/API docs must be both correct and useful at the point of use—never misleading, stale, or attached to the wrong symbol.
Apply this checklist:
/** ... */ block is positioned so TypeScript attaches it to the intended declaration; avoid duplicate/orphaned JSDoc blocks.yield/API boundary.t('...') keys must be added to all locales.Example: document generator consumption when yielding views into a reused buffer
async function* readFileHandleChunks(fileHandle: FileHandle, sourceSize: number): AsyncGenerator<Buffer> {
const highWaterMark = 512 * 1024;
const buffer = Buffer.allocUnsafe(highWaterMark);
let position = 0;
while (position < sourceSize) {
const bytesRead = (await fileHandle.read(buffer, 0, Math.min(highWaterMark, sourceSize - position), position)).bytesRead;
if (bytesRead === 0) return;
position += bytesRead;
// CONTRACT: This is a view into a reused underlying buffer.
// Consumers must synchronously copy/consume the bytes before the next `yield`.
yield buffer.subarray(0, bytesRead);
}
}
If you make a behavioral change (output strings, semantics, validation rules, or i18n keys), treat documentation/comment updates as part of the same change set—otherwise the next developer will be guided by false information.
When handling security-sensitive interactions (authz/ownership, network callbacks, and untrusted execution), apply defense-in-depth at the boundaries: be precise about guarantees, bind authorization to explicit identities at creation time, validate inbound payloads before side effects, and isolate both execution and filesystem writes.
Practical rules: 1) Don’t overstate bypass behavior
2) Bind authorization explicitly; require exact-match on callbacks
3) Validate callback payload structure against stored state before calling responders
4) Only allow interactive actions for eligible inbound-human turns
5) Sandbox untrusted code with isolation parity; keep metadata out of the sandbox
gh calls or network calls that require credentials.6) Never write trusted outputs through untrusted worktrees
7) Constrain PR-facing writes to a single authorized path
Example (callback ingress validation pattern):
// 1) Owner-only: storedKey was recorded at card creation time.
const ok = normalizeOwner(callback.user) === storedKey;
if (!ok) return failClosed();
// 2) Answer-key defense-in-depth: indices must match stored questions.
const keys = Object.keys(payload.answers ?? {});
const valid = keys.every(k => {
const i = Number(k);
return Number.isInteger(i) && i >= 0 && i < storedQuestions.length;
});
if (!valid) return failClosed();
// 3) Only now call the responder/settlement.
await responder({ answers: payload.answers, ...otherFields });
Checklist your team can apply to any “interactive callback / bypass flag / untrusted execution” change: (authz binding) + (payload validation) + (eligibility definition) + (sandbox/credential boundaries) + (safe output path policy) + (single allowed write path).
When behavior is driven by config/flags (timeouts, scopes, feature gates, safe-mode), ensure every code path uses the same authoritative inputs and does not silently degrade.
Standards
1) No hardcoded environment overrides for timing: tool-call/polling waits must use env-aware defaults (or an explicitly justified env-aware formula), not fixed “one size fits all” timeouts.
2) Single source of truth for gates/flags: default parameter values must reference the current config gate accessor; avoid stale/legacy getters that can silently change semantics.
3) Scope correctness (and honesty): enforcement logic and user-facing warnings must match the settings schema/docs, including trusted scopes (e.g., SystemDefaults).
4) No machine-global security gates via per-workspace overrides: if a setting is intended to be consistent across the host, either ignore workspace scope for it or provide a deployment-level env var mechanism; otherwise mixed behavior will occur.
5) Mode parity (safe mode / special modes): status/reporting endpoints must use the same disablement and enforcement logic as execution paths.
6) Schema validity per version: fields that are dead in a given version must be removed from that version’s strict schema or explicitly reserved/documented.
7) Avoid global mutable config side effects: if you temporarily override module-level config (e.g., API host), restore it in a finally block.
Example: env-aware timeout instead of hardcoded
const toolCall = await rig.waitForAnyToolCall(
['write_file', 'edit'],
rig.getDefaultTimeout(),
);
Example: restore overridden host/config
const prev = getGhHost();
try {
setGhHost(window.host ?? undefined);
// ... audit calls ...
} finally {
setGhHost(prev);
}
Workflow logic changes can silently ship if tests don’t observe the exact contract your users/ops depend on. Adopt this checklist when writing/modifying tests around GitHub Actions scripts/workflows:
1) Assert the real user-visible contract
2) Make stubs/fakes record critical invariants
3) Drive every critical branch with fixtures
[] in fixtures if the production logic relies on that being sometimes non-empty.4) Scope assertions to the correct job/step
job('verify')) or step scoping (e.g., stepIn(job, step)) so the test proves the intended behavior.Example pattern (branch + contract + invariant):
PATCH /issues/comments/<id> (not POST), and the new body contains the exact verdict headline.This approach prevents the three common silent-failure modes shown in review: (a) tests only look at coarse substrings, (b) stubs discard the changed parameter so nothing is asserted, and (c) fixtures never reach the branch that would break in production.
When code relies on values or logic that can diverge from the rest of the system (CSS/layout, shared pagination sizes, status-to-UI rules, helper behavior), prefer a single source of truth.
Apply these rules:
SESSION_LIST_PAGE_SIZE).getComputedStyle(...) (including gap) instead of subtracting assumed pixels.taskStatus -> label/tone/icon (use a config object) so adding a new status can’t mismatch UI parts.getString(...) rather than inlining type checks that may drift.Example (centralized status mapping + constants):
const TASK_STATUS_CONFIG = {
completed: { labelKey: 'system.taskCompleted', tone: 'success', Icon: CircleCheckIcon },
failed: { labelKey: 'system.taskFailed', tone: 'error', Icon: CircleXIcon },
cancelled: { labelKey: 'system.taskCancelled', tone: 'neutral', Icon: CircleMinusIcon },
} as const;
const statusConfig =
(taskStatus && TASK_STATUS_CONFIG[taskStatus as keyof typeof TASK_STATUS_CONFIG]) ??
{ labelKey: 'system.taskNotification', tone: 'neutral', Icon: InfoIcon };
const page = await workspace.client.listWorkspaceSessions(cwd, {
pageSize: SESSION_LIST_PAGE_SIZE,
});
const style = getComputedStyle(header);
const headerGap = parseFloat(style.gap) || 0;
This reduces silent UI breakage when constants, CSS, or helper behavior change over time.
Ensure your tests are mutation-effective: they must fail when the implementation changes in ways that break intended behavior. Avoid vacuous assertions, and don’t confuse “a test exists” with “the test would catch the real bug.”
Practical standards: 1) Pin the observable contract, not a computed tautology
expect(extract(a)).toBe(extract(b)) where both sides compute the same fallback that returns undefined/empty on many mutations, the test may stay green even when behavior is broken.2) Cover the actual branch that enforces safety
3) Add boundary and shape variants where logic branches
ApiError-shaped quota errors vs plain strings).4) Use an “equivalent mutant” check before escalating severity
Example: avoid a vacuous “either/or” success assertion
// Wrong pattern (can pass on silent tool failure):
expect(toolCall || updated).toBe(true);
// Mutation-effective pattern:
if (toolCall) {
expect(updated, 'file must update when tool was called').toBe(true);
}
expect(toolCall || updated, 'must succeed via tool-call or correct content').toBe(true);
Example: test exact boundaries
// Instead of only “over limit” and “under limit”, also test equality.
expect(validateReason('x'.repeat(8000))).toBe(true);
expect(validateReason('x'.repeat(8001))).toBe(false);
Example: test alternate error shapes
it('treats ApiError-shaped quota exhaustion as exhausted', () => {
const err = { error: { code: 429, message: 'quota exhausted', status: 'RESOURCE_EXHAUSTED' } };
expect(isQuotaExhaustedError(err)).toBe(true);
});
Adopt this as a review checklist for the Testing category:
When designing client-facing interfaces (request payloads, component props, or render-slot “host action” APIs), treat optional features and host-provided children as contracts—not assumptions.
Apply these rules:
1) Capability-gate request fields: Only send optional parameters when the server/daemon advertises support. Keep gating consistent across all call sites.
2) Don’t rely on opaque host forwarding: If your component needs to identify/trigger host actions after re-parenting (e.g., overflow menu), don’t depend on injected props/selectors being forwarded by arbitrary ReactNodes. Use wrappers, structured action descriptors (id/label/callback), or require/tightly type a forwarding contract (documented + enforced).
3) Keep shared state props consistent: If sibling controls are disabled/enabled based on the same state (e.g., approval pending), pass the computed value through—avoid hardcoded props.
4) Make UX fallbacks explicit: Avoid hardcoded non-localized labels and ensure accessible naming is produced from contract inputs (e.g., prefer aria-label/title, and don’t create unlabeled menu items from icon-only children).
Example (capability-gated request param):
const params: any = {
pageSize: SESSION_LIST_PAGE_SIZE,
archiveState: 'active',
};
if (capabilities.session_source_metadata) {
params.sourceType = WEB_SHELL_SESSION_SOURCE_TYPE;
}
await listWorkspaceSessions(params);
Example (avoid opaque render-slot assumptions—use descriptors instead of ReactNode host actions):
type PaneAction = { id: string; label: string; onSelect: () => void };
function PaneHeaderActions({ actions }: { actions: PaneAction[] }) {
return (
<DropdownMenu>
{actions.map(a => (
<DropdownMenuItem key={a.id} onSelect={a.onSelect}>
{a.label}
</DropdownMenuItem>
))}
</DropdownMenu>
);
}
When automating GitHub (or similar) APIs from CI/workflows, treat API access like production client code: make it correct, complete, and safely reconcilable.
Standards 1) Use the approved API client/tooling
gh api (or your org’s standard client) over raw curl to avoid missing auth headers, API version headers, and content negotiation.2) Never assume list endpoints fit in one page
gh api --paginate ... --jq ...).3) Ensure query filters match the user-facing intent
hours), the GraphQL/REST query must apply that window to all relevant connections, or explicitly document the asymmetry.4) Reconcile managed state only where provenance is knowable
desired, or intersect with last workflow-managed set).Example pattern
set -euo pipefail
# 1) Prefer gh api over curl
# gh api "repos/$GITHUB_REPOSITORY/releases/tags/$RELEASE_TAG" > release.json
# 2) Paginate list results
reviewed_users="$(gh api --paginate "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews?per_page=100" \
--jq '[.[].user.login]')"
# 3) Apply filters that match inputs (conceptual)
# Ensure both issues and PRs use since/updatedAt bounds when hours is provided.
# 4) Safe reconciliation (conceptual)
# Only remove reviewers that were previously added by *this* workflow run.
# managed="$(...)" # compute current requested_reviewers
# owned="$(...)" # reviewers your workflow previously managed (tracked/provable)
# desired_owned="$(...)" # desired within owned set
# new_managed = (managed - owned) + desired_owned
Applying these rules prevents silent coverage gaps, incorrect reconciliation churn, and maintenance drift in authentication/versioning across API calls.
In automation scripts/workflows, never fail or skip important work silently. If a condition decides to omit a capability/flag, or if a command fails with diagnostics discarded or a sentinel fallback is used, emit an explicit warning (or notice) that includes the relevant inputs and captured error output.
Apply this especially to:
--notes-start-tag when an ancestor check passes).2>/dev/null (capture stderr and log it).stat falling back to 0), which should always log computed values or the failure.Example patterns:
# 1) Conditional skip with warning
if [[ -n "$PREVIOUS_RELEASE_TAG" ]] && git merge-base --is-ancestor "$PREVIOUS_RELEASE_TAG" HEAD; then
NOTES_START_TAG_FLAG+=(--notes-start-tag "$PREVIOUS_RELEASE_TAG")
elif [[ -n "$PREVIOUS_RELEASE_TAG" ]]; then
echo "::warning::PREVIOUS_RELEASE_TAG ($PREVIOUS_RELEASE_TAG) is not an ancestor of HEAD; omitting --notes-start-tag"
fi
# 2) Don’t discard stderr; surface it
result="$(gh api graphql -f query="mutation { minimizeComment(input: {subjectId: \"${node_id}\", classifier: OFF_TOPIC}) { minimizedComment { isMinimized } } }" \
--jq '.data.minimizeComment.minimizedComment.isMinimized' 2>&1)" || true
if [[ "$result" != "true" ]]; then
echo "::warning::Failed to minimize ${node_id}: ${result}"
fi
# 3) Log computed/fallback values
RUNNER_UID="$(stat -c '%u' "$RUNNER_TEMP" 2>/dev/null || stat -f '%u' "$RUNNER_TEMP" 2>/dev/null || echo 0)"
RUNNER_GID="$(stat -c '%g' "$RUNNER_TEMP" 2>/dev/null || stat -f '%g' "$RUNNER_TEMP" 2>/dev/null || echo 0)"
echo "Ownership restoration: RUNNER_UID=$RUNNER_UID, RUNNER_GID=$RUNNER_GID"
Outcome: operators/oncall can immediately tell whether a path was intentionally skipped, what input caused it, and what underlying command error occurred—reducing 3AM guesswork.
All CI/CD-related script/workflow tests must be executed in CI, and they must assert the behaviors that matter in production—especially fail-closed security gates and correct step ordering.
Apply it as a checklist:
1) Wire tests into CI: if you have scripts/tests/*.test.js (or npm run test:scripts), add a workflow step that runs it. Don’t rely on developers running tests locally.
2) Test logic, not strings alone: for security-sensitive workflow gating, include negative/deny scenarios and verify the intended allow/deny behavior (and any explanation/telemetry flags).
3) Assert ordering, not just presence: when workflow steps sweep/cleanup temporary dirs or delete symlinks, verify cleanup happens after any artifact staging/copying that must dereference symlinks, and before the final launch/upload step.
Example (ordering assertion pattern):
const sweep = "find tmp -maxdepth 2 -type d -name '*-verify-*' -exec rm -rf {} +";
const stepText = getRunStepText(); // however your test builds/extracts it
const cpIndex = stepText.indexOf('cp -r');
const sweepIndex = stepText.indexOf(sweep);
expect(cpIndex).toBeGreaterThan(-1);
expect(sweepIndex).toBeGreaterThan(-1);
expect(cpIndex).toBeLessThan(sweepIndex); // fail if deletion moves earlier
This prevents regressions where CI wiring is missing and prevents “false green” tests where commands exist but run in the wrong order or weaken fail-closed gating.
Use fail-safe error handling everywhere in long-running / retrying flows: cleanup must be guaranteed, state/cursors must follow the intended retry semantics, and errors must remain diagnosable.
Apply these rules: 1) Cleanup in finally, not best-effort.
2) Decide per error kind: retry, terminal-skip, or bubble.
3) Never “silently succeed” after a failed dispatch.
4) Preserve diagnostics.
throw new X(message, { cause: error }).5) Classify timeouts/cancellations/quotas correctly.
Example pattern (cursor + fail-safe dispatch):
async function processBatch(items: Item[], cursor: Cursor) {
let firstError: unknown;
for (const item of items) {
try {
const ok = await dispatch(item);
if (ok) cursor.markHandled(item.id);
// advance cursor for success (or terminal skip)
} catch (err) {
if (isTerminal(err)) {
// skip permanently but advance cursor so you don’t wedge
cursor.markHandled(item.id);
continue;
}
// retryable: do NOT advance cursor/dedup keys
firstError ??= err;
}
}
if (firstError) throw firstError;
cursor.advanceToLatest();
await cursor.save();
}
function isTerminal(err: unknown): boolean {
// 404/410 patterns; also treat auth/permission without retry-after as terminal
return err instanceof HttpError && (err.status === 404 || err.status === 410);
}
This standard prevents the common failure modes seen across the discussions: orphaned state from missing cleanup, lost messages from swallowing/“marking handled” on failed dispatch, infinite poll livelocks from not advancing cursor, and operator-blind failures from lost error context.
Use strict, non-silent error handling and evidence gating across CI scripts and publish steps—especially when untrusted inputs and reruns are involved.
Apply these rules: 1) Never hide failing diagnostics
/dev/null without capturing them into logs.2) Make “no match/empty input” non-fatal under set -e
set -euo pipefail, commands like grep can exit 1 when nothing matches; treat that as an expected state (e.g., “empty blocklist”) instead of aborting.3) Validate output marshalling before downstream parsing
$GITHUB_OUTPUT, use the multiline-safe <<EOF form (heredoc). Never rely on single-line key=value for JSON arrays.4) Treat pipelines as a set of outcomes
set -e/pipefail, don’t trust only PIPESTATUS[0]. Record both producer and consumer stages (e.g., agent + tee) and downgrade “pass” to infra error if output writing/truncation failed.5) Bound all “read/truncate” operations to avoid SIGPIPE under pipefail
tr|head/similar pipelines (e.g., head -c 4096 file | ...).6) Gate substantive/terminal publish updates on validated artifacts
success.7) Classify infra vs PR failures using trusted signals only
Illustrative bash pattern (combine rules 2,4,6):
set -euo pipefail
# 1) empty-match is expected
BLOCKED_USERS="$(grep -vE '^\s*#' blocklist | ... | sort -u || true)"
# 2) pipeline status: capture both stages
set +e
timeout 25m run_agent | tee output.jsonl
PIPE_STATUS=(${PIPESTATUS[@]})
AGENT_CODE=${PIPE_STATUS[0]}
TEE_CODE=${PIPE_STATUS[1]:-0}
set -e
verdict='pass'
if [ "$AGENT_CODE" -ne 0 ] || [ "$TEE_CODE" -ne 0 ]; then
verdict='infra-error'
fi
# 3) only publish substantive if report exists
if [ "$verdict" = 'pass' ] && [ -f tmp/verify-*/report.md ]; then
publish_substantive
else
publish_weak_results_unavailable
fi
Outcome: fewer silent CI failures, correct publish/evidence preservation across reruns, and accurate infra-vs-PR labeling so developers don’t waste time rerunning code when the true problem was infrastructure (or the opposite).
Require every documentation change to pass two gates: (1) strict doc-schema conformance, and (2) factual/behavioral accuracy against the implementation and shipped artifacts.
Gate 1: Conformance
When to Use / Prerequisites sections).windows if commands/guidance are cross-platform).Gate 2: Accuracy & consistency
hf if prerequisites still install huggingface-cli; don’t present CLI-only commands like /reload as gateway/user-session steps).Example checklist (apply to every PR):
SKILL.md) meet all formatting/limit rules (one-sentence/≤60-char description, required sections, required metadata)?If any item fails, the doc must be corrected (or the claim narrowed) before merge.
Treat every transition from “untrusted / scoped data” into a sensitive sink (shell execution, subprocess credentials, HTTP fetch, filesystem writes, and API-triggered work) as a security seam. Enforce fail-closed policy at that seam:
self._check_auth(request) (or the equivalent gateway dashboard auth middleware) before parsing bodies or triggering work; avoid any endpoint that starts actions without the existing auth boundary.UnscopedSecretError by falling back to os.environ. Avoid process-global credential aliasing (e.g., setting env vars to influence client construction) unless the subprocess/sanitizer inheritance is explicitly rechecked.subprocess.run([...], shell=False, ...). If a string command is unavoidable, quote/escape with platform-appropriate shell quoting before any concatenation and add regression tests that include metacharacters like ; and |.Example pattern (auth + safe command execution):
async def handler(self, request):
auth_err = self._check_auth(request)
if auth_err:
return auth_err
body = await request.json()
user_supplied = str(body.get("command_args", ""))
# Prefer argv list-mode
argv = ["some-binary", "--arg", user_supplied] # no shell
# subprocess.run(argv, shell=False, check=True, ...)
return web.json_response({"ok": True})
Adopting this “seam-first, fail-closed” standard prevents common regressions: injected shell tokens, secret-scope bypasses, unguarded public triggers, and redirect-based SSRF/TOCTOU.
Establish a single concurrency standard: in async code, never block the event loop; in multi-thread/state-machine code, make ownership and cancellation atomic; and in cleanup/shutdown, use bounded, interrupt-friendly paths.
1) Keep async nonblocking
subprocess.run, CPU-heavy work (ffprobe/ffmpeg, compressors, summary generation), synchronous SDK calls, or blocking I/O must be offloaded.result = subprocess.run([…], timeout=60)
result = await asyncio.to_thread(subprocess.run, […], timeout=60)
result = await adapter._run_blocking(func, *args)
2) Re-check cancellation/flags after waits
- If a worker can be paused in `Event.wait()` (or similar), it must re-check the controlling mode/flag at every boundary where it could restart capture/playback/processing.
- Pattern:
```py
await voice_done.wait()
if cli_ref._voice_continuous is False:
return # cancel boundary
3) Lock/claim correctly; snapshot atomically
4) Shutdown/cleanup must be bounded and interrupt-friendly
shutdown(wait=True)) before the code path that needs to deliver an interrupt/watchdog action.pool.shutdown(wait=True, cancel_futures=True)
pool.shutdown(wait=False, cancel_futures=True)
5) Add regression coverage for the real concurrency boundary
- For cross-thread queueing (e.g., `put_threadsafe()`), tests must involve a real worker thread, not only same-loop calls.
- For ownership/leases and cross-process locks, add OS-process regressions (where supported) to validate the intended guard behavior.
---
## Security Invariants Testing
<!-- source: QwenLM/qwen-code | topic: Security | language: Yaml | updated: 2026-07-28 -->
Treat CI/workflow security like production security code: define explicit invariants, enforce them defensively, and lock them with executable regression tests—especially in workflows that run in privileged contexts (e.g., pull_request_target) or execute untrusted PR code.
Apply these rules:
1) Pin third-party actions by immutable SHA
- Never use mutable tags (e.g., actions/cache@v4) in privileged contexts.
- Require the same “40-char SHA pin” convention for all actions.
2) Fail-closed authorization and principal resolution
- Gate execution on the correct identity (e.g., PR author if that’s the executed code path).
- Reject on missing principal, missing/empty permissions, 404s, or any API failure.
- If a run waits in a queue, re-check permissions immediately before executing.
- Pin the authorized head OID and refuse to run if checkout HEAD differs.
3) Credential minimization and strict scoping
- Keep tokens out of environments where untrusted code runs.
- Use step-level env only for the steps that need them.
- For pull_request_target checkouts: use persist-credentials: false.
4) Prevent control/data-plane poisoning
- Never select “previous report” or “running status” purely by prose/substring; use dedicated machine markers.
- For agent-produced reports: validate structured inputs (e.g., totals consistency) and HTML-escape untrusted content.
- Add executable tests for escaping and truncation behavior.
5) Filesystem hardening for self-hosted/persistent workspaces
- Assume symlinks and prior run state can be adversarial.
- Use symlink-safe deletion (unlink entries without following) and canonicalize any delete targets to remain inside the workspace.
- Ensure cleanup happens both before and after untrusted execution, with regression tests that fail when safety guards are removed.
6) Add/extend executable regression tests for invariants
- If a security invariant exists (repo guard, persist-credentials, cache restore-only, marker usage, escaping implementation, symlink-safe cleanup, re-auth/head pinning), it must be asserted by an automated workflow test.
Minimal examples (adapt patterns):
Action pinning:
```yaml
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.x.y pinned
Avoid embedding step outputs directly into shell:
- name: Record receipt
env:
POOL_RUN_ID: '${{ steps.dispatch.outputs.run_id }}'
run: |
printf '%s\n' "Pool run: $POOL_RUN_ID" >> "$GITHUB_STEP_SUMMARY"
Fail-closed principal handling (pattern):
# deny on missing/empty principal or permission API failures
if [ -z "$PR_AUTHOR" ] || ! permission="$permission_api_result"; then
echo "decision=skip" >> "$GITHUB_OUTPUT"
exit 0
fi
case "$permission" in
admin|maintain|write) : ;;
*) echo "decision=skip" >> "$GITHUB_OUTPUT"; exit 0 ;;
esac
Run the above as a checklist for every security-critical workflow change: if you can’t test the invariant, you don’t truly have one.
When code review finds duplicated logic or repeated formatting/constants, treat it as a “single source of truth” violation. Factor shared logic into a helper/module and reuse it everywhere; avoid hardcoded literals where an existing helper/constant exists; and keep established idioms consistent.
Guidelines:
type New = Old;) or imported from a shared module.timer.unref?.() pattern over verbose type guards when they’re equivalent).undefined immediately overwritten on the next line); remove dead assignments when refactoring.Example (helper extraction):
// helpers.ts
export function extractParentToolNames(generationConfig: unknown): string[] {
// ... shared extraction logic ...
return names;
}
// call sites
const names = extractParentToolNames(generationConfig);
Example (constant for repeated literals in tests):
const INITIAL_CONTENT = 'original content';
expect(input.content).not.toBe(INITIAL_CONTENT);
CI/CD workflows should enforce state invariants across steps, runs, and runners: later steps must only execute when earlier phases truly produced a valid outcome, and all per-run state must be cleaned/flushed and permission-safe—especially on persistent self-hosted runners.
Apply these rules:
1) Gate downstream steps on all relevant phase outputs
gate -> verify -> push, the push step’s if: must include both gate success and verify’s final result (e.g., not no-fixes).# good: push requires gate=fixed AND verify != no-fixes
- name: Push and open PR
if: ${{ steps.gate.outputs.result == 'fixes' && steps.verify.outputs.result != 'no-fixes' }}
2) Keep published artifacts consistent after reverts/aborts
verify reverts commits, update the same data files/records you uploaded earlier (e.g., findings.json) so downstream consumers never see stale statuses.3) Flush per-run temp/state on persistent runners
rm -rf "$RUNNER_TEMP/verify-results" "$RUNNER_TEMP/verify-context" 2>/dev/null || true
mkdir -p "$RUNNER_TEMP/verify-results" "$RUNNER_TEMP/verify-context"
4) Restore both ownership and write permissions after hardening
chown without re-chmod can still break later cleanups/checkouts (EACCES). Restore mode to allow deletes/unlinks.chown -R "$RUNNER_UID:$RUNNER_GID" "$GITHUB_WORKSPACE" || true
chmod -R u+rwX "$GITHUB_WORKSPACE" || true
5) Make workflow behavior robust to cache misses and checkout edge-cases
chown when caches may miss.6) Prevent CI/resource hangs with explicit bounds
timeout-minutes.7) Keep concurrency predicates exact
concurrency.group logic matches the job’s runnable triggers; otherwise one command (e.g., /verify) can displace another (e.g., /triage).If your workflow cannot be proven under: (a) cancellations, (b) persistent runner reuse, (c) cache misses, and (d) permission/mode changes, it’s a CI reliability issue—fix it with the invariants above before merging.
Coding standard for recovery/error paths: make failure and recovery behavior truthful, gated, and user-consistent.
Apply this rule set: 1) Ground messages and state on authoritative runtime outcomes (avoid predicates/flags that can drift from behavior). If the only way to know is to attempt (e.g., reset/clear), attempt and then report based on the result. 2) Choose degradation vs failure by comparing which one is less misleading to the user/UI.
Illustrative pattern (retry gating + bounded empty fallback):
if provider_errored || cancel_token.is_cancelled() {
surface_error(provider_err);
return;
}
let visible_content_streamed = last_assistant_text_not_empty || surfaced_thinking_in_turn || streamed_images;
if visible_content_streamed {
// Avoid duplicate/incoherent resend.
surface_error(provider_err);
return;
}
let empty_response = no_tools_called && last_assistant_text.is_empty();
if empty_response {
if empty_turn_retries < MAX_EMPTY_TURN_RETRIES {
empty_turn_retries += 1;
warn!("Empty provider response; retrying {}/{}", empty_turn_retries, MAX_EMPTY_TURN_RETRIES);
messages_to_add.clear(); // don’t persist empty turn
continue;
}
// After retries, surface a real message.
let msg = Message::assistant().with_text(EMPTY_TURN_MESSAGE);
yield AgentEvent::Message(msg.clone());
messages_to_add.push(msg);
}
When API behavior depends on client/provider capabilities, request-field validity, or protocol ordering, implement it via explicit contracts—not heuristics—and ensure the exposed responses match the runtime’s effective configuration.
Apply these rules: 1) Capability-first (no guessing). If the server needs client terminal/shell dialect, OS/execution context, or other environmental details, require them via a typed capability during initialization; keep server-local inference only as a backward-compatible fallback. 2) Schema-correct request emission. Only send provider-specific fields (or attachment shapes) to the endpoints/models that accept them. Prefer Option/guarded emission over “best effort” extra fields. 3) Normalize then expose. If you build a local ModelConfig/limits for an endpoint, ensure the returned API view matches what the runtime actually uses after provider normalization. 4) Stable machine semantics. For machine-readable modes, keep output purely structured; for human modes, separate prose from metadata. Ensure error/status/stop_reason are consistent. 5) Tests that pin ordering. When correctness relies on evaluation/handling order (e.g., deciding which error to return), add table-driven tests that lock the intended sequence.
Example pattern (capabilities + fallback):
// During initialize: client-provided typed capability
struct ClientCapabilities {
// e.g. typed goose initialize metadata
terminal_shell: Option<TerminalShellCapability>,
}
// On terminal/create: use capability; fallback only for legacy clients
fn terminal_shell_command(cap: &ClientCapabilities) -> (String, Vec<String>) {
if let Some(c) = &cap.terminal_shell {
(c.executable.clone(), c.args_prefix.clone())
} else {
// Backward-compatible fallback (server-owned)
(server_default_shell(), vec![])
}
}
Outcome: fewer cross-provider breakages, fewer “works in one mode” inconsistencies, and API responses that reliably reflect the behavior clients will observe at runtime.
Behavioral configuration must be documented and wired through the supported config system, with examples matching the actual runtime resolution.
Apply these rules:
1) Non-secret settings → config.yaml
HERMES_*) unless there is an explicit, accepted config-system feature.~/.hermes/config.yaml, namespaced by the owning feature/skill (e.g., kairos:, tts:, etc.).2) .env is secrets-only
~/.hermes/config.yaml..env / secret stores.3) Docs must match real default resolution
4) Installation/runtime paths must be accurate
SKILL_DIR/path instead of repo-relative paths.5) Avoid documenting unsupported keys until implemented
Example (~/.hermes/config.yaml):
# Non-secret behavior
kairos:
enabled: true
schedule: "weekly"
terminal:
shell_init_files: [] # explicit list replaces OS defaults
Example (.env):
OPENAI_API_KEY=***
# secrets only
Default to explicit resource budgets and ensure they’re actually enforced.
Apply these rules in code review: 1) Bound inputs and remote pagination
perPage/maxPages) and must not re-walk a forever-growing queue.2) Eliminate repeated expensive work in hot loops
3) Make enforcement observable/tested
Example (bounded pagination + draining):
const todos = await this.api.TodoLists.all({
state: 'pending',
perPage: 100,
maxPages: 5,
});
for (const todo of todos) {
if (unsupported(todo)) {
// must drain/skipped items to avoid re-fetch forever
await this.api.TodoLists.done({ todoId: todo.id });
continue;
}
await this.process(todo);
await this.api.TodoLists.done({ todoId: todo.id });
}
Example (memoize stable resolved roots):
// once per config/session
const resolvedPinnedRoots = memoryRoots.map((root) =>
realpathExistingOrNew(path.resolve(root, AUTO_MEMORY_PINNED_DIRNAME)),
);
function isProtectedPinnedMemoryPath(resolvedCandidate: string|undefined, literalCandidate: string) {
return memoryRoots.some((_, i) =>
isWithinRootCaseInsensitive(literalCandidate, literalPinnedRoots[i]) ||
(resolvedCandidate && resolvedPinnedRoots[i] &&
isWithinRootCaseInsensitive(resolvedCandidate, resolvedPinnedRoots[i]!))
);
}
4) Don’t endorse unverifiable perf claims
In async/concurrent code, always make cancellation/timeout behavior correct, deterministic, and safe against stale work.
Coding standard
1) Bound the full operation: put tokio::time::timeout around the entire request/handshake/startup sequence that must not hang (including setup/config/mode steps).
2) Cancel/cleanup what you own: if a timed-out Future is dropped, ensure any spawned process/task owned by that component is cleaned up via kill_on_drop(true) or cancellation-aware control messages. Also propagate cancellation tokens into nested operations.
3) Race stream polling vs cancellation: don’t rely on stream.next().await to return on cancel; use tokio::select! and forward provider.cancel(...). Ensure cancel forwarding still happens even if the consumer drops the stream.
4) Reject stale updates: when superseding sessions/providers, use a generation key (e.g., active_session_id) set only after successful setup; drop notifications/updates whose id doesn’t match. Abort/clear old notification receiver tasks on provider recreation.
5) Don’t lose ordered protocol messages: use awaited send() (not lossy try_send) for ordered streams where sequence/termination matters.
Pattern (timeout + cancellation forwarding + stale filtering)
use tokio::{select, time};
let models = time::timeout(SUPPORTED_MODELS_TIMEOUT, async {
let provider = create_provider().await?;
provider.fetch_supported_models().await
}).await??;
// In an event loop handling session notifications:
let active_session_id = /* set only after successful session/new */;
while let Some(update) = rx.recv().await {
if update.session_id != active_session_id { continue; }
handle_update(update);
}
// In a provider reply loop:
loop {
let next = select! {
biased;
_ = cancel_token.cancelled() => {
provider.cancel(&session_id).await;
break;
}
msg = stream.next() => msg,
};
if next.is_none() { break; }
handle_msg(next.unwrap());
}
Adopting this standard prevents: (a) hung handshakes that outlive the caller, (b) orphaned child processes after timeout, (c) “cancel didn’t stop backend” bugs, (d) stale session/provider updates corrupting state, and (e) ordering/termination regressions in protocol streams.
When adding or modifying tests, favor behavioral contract coverage over brittle implementation/shape checks.
Apply these rules:
Example pattern (deterministic time):
class FakeTime:
def __init__(self, real_time, start=1000.0):
self._real = real_time
self._now = start
def monotonic(self):
return self._now
def advance(self, seconds):
self._now += seconds
def __getattr__(self, name):
return getattr(self._real, name)
def test_silence_threshold(monkeypatch):
import time as real_time
fake = FakeTime(real_time)
monkeypatch.setattr("tools.voice_mode.time", fake)
# drive the timeline deterministically
fake.advance(0.05)
# assert state transitions...
This approach makes tests resilient to harmless refactors while still catching real regressions in control flow, branching, and platform-dependent behavior.
Enforce null/optional safety at every boundary: treat external API data and persisted JSON as untrusted, validate before dereferencing, and ensure normalization/parsing preserves only values that satisfy the declared type contract. Never let invalid optional fields “leak through” via ...raw spreads or falsy-based numeric checks; degraded modes must remain structurally consistent so downstream consumers don’t misinterpret missing facts.
Practical rules:
normalize* functions, construct the output from known fields (or delete known invalid fields after ...raw). Avoid ...raw followed by conditional spreads that can’t overwrite wrong-typed values.0 is valid; check typeof x === 'number' && Number.isFinite(x).null/non-object inputs.unknown/null) rather than silently degrading to “unchanged”.Example (safe normalization + “never throws”):
type Out = { hostAuthToken?: string };
function stringOrUndefined(v: unknown): string | undefined {
return typeof v === 'string' ? v : undefined;
}
export function normalizeWorker(raw: unknown): Out {
if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return {};
const r = raw as Record<string, unknown>;
// Do NOT `return { ...raw, ... }` (it can leak wrong-typed optional fields).
return {
hostAuthToken: stringOrUndefined(r.hostAuthToken),
};
}
export function parseReceiptIds(raw: string): number[] {
try {
const parsed = JSON.parse(raw);
if (parsed === null || typeof parsed !== 'object') return [];
const o = parsed as Record<string, unknown>;
const ids = Array.isArray(o.reviewIds)
? o.reviewIds
: typeof o.reviewId === 'number'
? [o.reviewId]
: [];
return ids.filter((x): x is number => typeof x === 'number' && Number.isInteger(x));
} catch {
return [];
}
}
Applying this will prevent both crash-on-null (wedge/stall) and silent misclassification (wrong “clean” or “unknown” signals).
When implementing cursor-based dedup/caching for event dispatch, ensure the dedup “key space” matches the real uniqueness of what you’re trying to prevent:
Practical template:
// 1) Dedup key must change when the triggering content changes.
const notifKey = `${notification.id}|${notification.updated_at}`; // not just notification.id
if (this.isDispatched(this.cursor.dispatchedNotifications, notifKey)) return;
// 2) Dispatch
await this.handleInbound(envelope);
// 3) Persist dedup keys for the exact items you dispatched
this.recordDispatched('dispatchedComments', dedupKey);
this.recordDispatched('dispatchedBodies', `${chatId}|${threadId}`);
this.recordDispatched('dispatchedEvents', triggerKey);
// 4) When re-discovering triggers, include both bounds
const event = events.findLast((candidate) => {
const t = candidate.created_at;
return t && t <= ctx.maxUpdatedAt && t > ctx.windowSince;
});
Acceptance checklist for reviews: 1) Every dispatch path has a corresponding, persisted dedup record (comments/bodies/events) on success. 2) Dedup keys include all dimensions needed to distinguish distinct “things to dispatch.” 3) Trigger search uses the same window bounds as the comment/body fetch logic. 4) Cursor trimming covers every dedup bucket you rely on. 5) HTTP read/caching headers are only applied on non-error response branches (or explicitly proven safe).
Default to “do the minimum possible work per hot-path update.”
Apply these checks: 1) Early-exit before side effects
2) Keep props/callbacks stable during streaming
React.memo’d (or any memoized subtree), don’t pass freshly-created inline handlers every render. Use useCallback (and useMemo for derived values) so shallow prop comparisons remain true.3) Don’t recreate observers/effects due to irrelevant dependencies
ResizeObserver/event listeners, only depend on values actually used by the effect. If the effect body doesn’t read a dependency, removing it prevents unnecessary teardown/re-setup during frequent rerenders.4) Throttle at the right stage + memoize expensive transforms
5) Detect changes against consistent baselines
Example (stable handler + throttled transform):
const handleRightPanelOpen = useCallback((request: TurnOutputOpenRequest) => {
if (request.kind === 'subagent') {
onRightPanelOpen?.({ /* ... */ });
}
}, [onRightPanelOpen]);
const throttledContent = useThrottledValue(content ?? '', isStreaming);
const renderedContent = useMemo(() => {
if (throttledContent && source && sourceMarkdown?.transformMarkdown) {
return sourceMarkdown.transformMarkdown(throttledContent, { source });
}
return throttledContent;
}, [throttledContent, source, sourceMarkdown?.transformMarkdown]);
Use this standard to review PRs that touch streaming, parsing, rendering, observers, and settings-change detection.
When adding or modifying caching/deduplication, ensure the cache identity (routing + key + scope) matches the exact contract where reuse is valid.
Key rules:
Example (mode-gated dedupe key):
def should_dedupe(event_guid: str, *, use_socketio: bool) -> bool:
# Dedupe only applies to Socket.IO duplicate suppression.
return use_socketio and bool(event_guid)
Example (scoped config cache):
_config_cache_by_home = {}
def load_audit_config_scoped(hermes_home: str) -> dict:
key = hermes_home
if key in _config_cache_by_home:
return dict(_config_cache_by_home[key])
cfg = compute_cfg(hermes_home)
_config_cache_by_home[key] = cfg
return dict(cfg)
Example (signature compatibility without secret material):
Apply these checks during code review: “Is this cache used by multiple call paths/modes? If so, is reuse gated correctly and does the key include all compatibility dimensions? Is the cache bounded and scoped to the correct profile/lifecycle?”
When implementing concurrent async workflows with callbacks (Stop/Submit/Cancel, permission settlement, card actions), make the operation safe against stale/foreign/parallel events by using atomic identity validation plus a synchronous “claim” before any awaited side effects.
Apply these rules:
Example (pattern for exact-run Stop):
async function cancelRunFromCard(expectedRunId: string, ownerKey: OwnerKey): Promise<boolean> {
// 1) parse/validate owner + callback identity (no awaits yet)
if (!isOwnerMatch(ownerKey)) return false;
// 2) synchronous claim of the current live record
const active = getCurrentActivePrompt(); // atomic read
if (!active || active.runId !== expectedRunId) return false;
const claim = tryClaim(active); // must be synchronous
if (!claim) return false;
// 3) only now do awaited side effects
const ok = await channelBase.cancelExactRun(active.sessionId, expectedRunId);
if (ok) {
blockNewStreamingChunks(active.runId);
commitStoppedProjection();
claim.releaseSuccess();
} else {
claim.release(); // keep card active for retry
}
return ok;
}
Adopt this as a standard for any callback-driven cancellation/submission path so parallel runs and near-simultaneous callbacks cannot corrupt state or show incorrect success to users.
When adding concurrency behavior (locks, in-flight guards, timeouts, retries, sampling), ensure three properties:
1) Atomic “check-and-act” before any await (avoid TOCTOU)
finally).2) Revalidate decisions against a fresh snapshot (avoid stale-snapshot races)
3) Cleanup must drain/await in-flight work even on failure (avoid teardown ordering bugs)
finally (or explicitly cancel them) so teardown (mode restore, session finalize) can’t occur while writes are still pending.Practical patterns
A) Atomic in-flight reservation
const inFlight = new Set<string>();
async function createSession(id: string) {
// synchronous check-and-add before any await
if (inFlight.has(id)) throw new Error('409 conflict');
inFlight.add(id);
try {
// do awaits/spawn here
await doWork();
} finally {
inFlight.delete(id);
}
}
B) Generation guard for out-of-order async completion
let gen = 0;
const lastApplied = { current: -1 };
async function refresh() {
const myGen = ++gen;
const value = await compute();
if (myGen !== gen) return; // stale completion
if (lastApplied.current !== myGen) {
lastApplied.current = myGen;
setState(value);
}
}
C) Double-sample + drift flag
const headBefore = await getPrHead();
const comments = await fetchAllComments();
const headAfter = await getPrHead();
const drift = headBefore !== headAfter;
// If drift, mark threads as staleWorktree or fail-closed.
D) Drain async writes in finally
let outputWrites = Promise.resolve();
try {
await pumpInputToPty();
await outputWrites;
return;
} finally {
// ensure pending writes finish or are cancelled before teardown
await outputWrites.catch(() => {});
}
If any change touches session creation, process spawning, locks/reservations, per-attempt retries, terminal/IO pipelines, or sampling across async boundaries, apply this checklist and add regression tests for the “race-changed-decision” branches—not just the happy path.
When implementing API-facing features, ensure request/response contracts are consistent across all code paths, correctly shaped for the upstream/downstream API, and complete under pagination/time-windowing.
Rules: 1) Keep serialization/parsing round-trips structurally identical
2) Validate upstream API method signatures and data fields
as unknown as ... casts.3) Make state transitions scope-safe; don’t mix per-item windows with global cursor side effects
4) Ensure pagination/windowing is complete (no permanent omission)
maxPages: 1/small page limits when correctness requires fetching all items in the time window.gh api --paginate), handle multi-page/NDJSON responses by flattening correctly and testing multi-page cases.Example patterns:
export function parseSessionId(pathname: string) { // Mirror writer: anchor to the last occurrence if writer used last-match logic. return pathname.match(/\/session\/([^/]+)\/?$/)?.[1]; }
// Test: expect(parseSessionId(buildSessionPathname(‘/app/session/’, ‘real-id’))) === ‘real-id’
- Avoid wrong-typed external calls by removing casts and using correct method signatures:
```ts
// Prefer typed signatures; do not do api.Issues.show(chatId, { issueIId: ... })
// If SDK says show(issueId, { projectId }), pass issueId as number and projectId as string.
const windowSince = this.cursor.lastProcessedAt; // authoritative
// ...when scanning trigger events, treat created_at <= windowSince as lower-bound
Adopting these rules prevents silent drops, permanent omissions, and contract drift—common failure modes in API integration code.
When building React “action slot” containers (inline vs overflow menus, responsive headers, hold/click controls), enforce these invariants:
1) Preserve host mount semantics
children in multiple parallel trees just to measure layout.2) Preserve DOM identity for event guarantees
document).3) Normalize host output before applying asChild/DOM-level props
<>...</> Fragments (or nested Fragments), flatten/normalize to concrete elements before wrapping with <DropdownMenuItem asChild> (or before cloning/annotating).4) Use the menu framework’s item components for accessibility + behavior
DropdownMenuContent. Wrap each action with the framework’s item component (e.g., DropdownMenuItem asChild) so roles/keyboard navigation and menu auto-close work consistently.5) Don’t rely on custom components forwarding unknown props
cloneElement to inject data-* or handlers unless you can guarantee the host component forwards unknown props via ...rest.<span style={{display:'contents'}} data-...>...</span>) so your attributes always land in the DOM.Example pattern (flatten + menu items + safe wrappers, no Fragment targets):
import { Children, Fragment, isValidElement, useMemo } from 'react';
function flattenToElements(node: React.ReactNode) {
const out: React.ReactElement[] = [];
for (const child of Children.toArray(node)) {
if (!isValidElement(child)) continue;
if (child.type === Fragment) {
out.push(...flattenToElements((child.props as any).children));
} else {
out.push(child);
}
}
return out;
}
function OverflowMenu({ children }: { children: React.ReactNode }) {
const elements = useMemo(() => flattenToElements(children), [children]);
return (
<DropdownMenuContent>
{elements.map((el, i) => (
<DropdownMenuItem key={el.key ?? i} asChild>
<span style={{ display: 'contents' }} data-action-index={String(i)}>
{el}
</span>
</DropdownMenuItem>
))}
</DropdownMenuContent>
);
}
Applying these rules prevents: duplicated subscriptions (double mount), broken menu roles/keyboard behavior (raw children), invalid DOM prop application to Fragments, click-proxy failures from missing prop forwarding, and interaction bugs from DOM identity changes during state transitions.
CI/CD verification steps must produce truthful, reproducible, human-visible evidence under hard environment constraints (time, filesystem, available tools, git history). Concretely:
1) Keep evidence visible across stages
status: "dropped", ensure it still appears in the human-facing report stream (not just an internal fixes list). Align .fixes/.reportOnly semantics so “dropped because verification failed” is still auditable.2) Make verification rerunnable (idempotent cleanup)
Example (safe worktree lifecycle):
# use a directory name that matches cleanup patterns (or remove explicitly)
git worktree add tmp/base-verify-tree HEAD^1
# ... run A/B ...
# always remove what you registered
git worktree remove --force tmp/base-verify-tree
3) Don’t promise evidence you can’t obtain
4) Run only gates your container can actually run; avoid mutating the PR tree
node scripts/lint.js --setup
# then only non-mutating checks (examples)
node scripts/lint.js --actionlint
# never call the mutating no-arg form that rewrites the PR tree
5) Validate controls don’t accidentally execute head code
6) Follow-up reports must snapshot the newest substantive evidence
/verify rounds, snapshot the latest substantive previous report (not transient “running/weak” marker comments) so prior unresolved findings aren’t erased.Applying these rules prevents CI/CD from silently hiding failures, failing reruns due to stale artifacts, overstating verification certainty, or producing non-comparable A/B results—raising reliability of automated gates and maintainer trust in the evidence.
When handling failures, treat “what happened” as a precise, testable contract—not an interpretation. Ensure (1) classification predicates are exact and consistent across docs+code, (2) failure causes are not overloaded, (3) cleanup/settlement invariants prevent stranded states, and (4) adapter/step contracts are enforced with safe fallbacks.
Apply these rules:
1) Freeze exact recovery predicates (spec == code)
2) Carry failure cause explicitly; never infer from an overloaded signal
3) Enforce exactly-once settlement and all parallel invariants
4) Validate “handled”/“presented” contracts; on violation, fall back to safe path
handled but didn’t perform the required settlement action (e.g., calling respond()), treat it as unsupported and continue the normal fallback so the request cannot get stuck.Example (pseudocode)
// 1) Exact error classification predicate
function classifyNoMatches(rg: { exitCode: number; stdout: string; stderr: string }) {
// NO MATCHES only when exitCode==1 and stderr is empty.
// (Do not key off stdout; JSON modes may emit stdout summaries.)
if (rg.exitCode === 1 && rg.stderr.length === 0) return 'no_matches';
return 'not_no_matches';
}
// 2) Adapter contract enforcement
async function presentWithContract(ctx: {
presentUserInputRequest: () => Promise<'presented'|'handled'|'unsupported'>;
respondMustBeCalledForHandled: () => void;
}) {
let respondCalled = false;
const wrappedRespond = () => { respondCalled = true; ctx.respondMustBeCalledForHandled(); };
const result = await ctx.presentUserInputRequest(/* uses wrappedRespond */);
if (result === 'handled' && !respondCalled) {
// Contract broken: fall through to existing permission formatter/sender.
return 'unsupported';
}
return result;
}
// 3) Typed settlement reasons (conceptual)
// settlementSignal.reason must distinguish answered_elsewhere vs request_cancelled/run_cancelled/expired.
Checklist before merge
When code decides “latest/first/anchor” behavior (events, schedule steps, URL/mention parsing), it must be deterministic by construction: sort inputs by the relevant timestamp/field before using positional selection (e.g., findLast), use dedup keys at the correct granularity to avoid permanent suppression, and make regex/parsers unambiguous with correct anchors/lookarounds for the target grammar.
Apply this standard: 1) Sort before positional selection
// Before selecting the most recent matching event
const events = await listEvents(...);
// Sort explicitly by created_at (or the actual field you reason about)
events.sort((a, b) => (a.created_at || '').localeCompare(b.created_at || ''));
const event = events.findLast((candidate) => {
// apply your temporal/logic predicates against candidate.created_at
return candidate.created_at && candidate.created_at > lowerBound;
});
2) Dedup keys must match the true identity of the unit being deduped
const notifKey = `${notification.id}|${notification.updated_at}`;
if (isDispatched(dispatchedNotifications, notifKey)) continue;
3) Regex/parsers: align grammar assumptions on both parse and emit sides
Why: Without these properties, seemingly small changes (different pagination alignment, an extra character allowed by a platform, or a dedup key that’s too coarse) turn into permanent missing triggers, duplicate dispatches, or wrong attribution.
When introducing or changing an API seam (hooks, callback payloads, lifecycle state transitions), require an explicit, end-to-end, type-safe contract that matches implementation and documentation.
Checklist:
runId) must be carried through the shared event/callback payload chain, not stored only in adapter-private state.AbortSignal.reason (typed as any in practice). Route settlement through a typed helper/callback so misspellings can’t compile.stopped event), require an explicit mapping table or explicit statement of how the state is derived.Example pattern (typed settlement wrapper):
type UserInputSettlementReason =
| 'resolved_outside_card'
| 'request_cancelled'
| 'run_cancelled'
| 'expired';
function setSettlementReason(signal: AbortSignal, reason: UserInputSettlementReason) {
// avoid writing to any-typed fields directly; centralize the mapping
(signal as any).__settlementReason = reason;
}
Example contract sketch (adapter-facing context):
interface ChannelUserInputRequestContext {
requestId: string;
sessionId: string;
runId: string;
target: SessionTarget;
ownerId: string;
request: PermissionRequestEvent['request'];
settlementSignal: AbortSignal;
respond(response: { /* RequestPermissionResponse + optional answers */ }): Promise<boolean>;
}
If any of the above can’t be satisfied, treat it as an API design bug: either the contract is incomplete, the correlation is not end-to-end, the semantics are not type-safe, or the documentation/API surface are out of sync.
When you correlate agent outputs, commit history, or prior workflow state across time, avoid fuzzy matching and “best-effort” heuristics. Instead:
1) Associate via stable identifiers (IDs), not text substrings.
2) Treat reviewer/record collections as sets and reconcile them with drift awareness (manually dismissed items must be excluded even if they never reviewed).
3) Persist the right state invariant for future runs—don’t overwrite marker state with post-drift values that erase manual decisions.
4) Use precise selectors for markers/reports (e.g., startswith(marker) and a dedicated “substantive report” marker), not “newest non-running”.
Example (stable association + precise marker selection):
# Commit message should include fix.id (written by the agent)
# Then drop matching becomes exact.
# e.g., msg contains(fix.id) rather than 30-char substring.
node -e '...
const droppedMsgs = process.env.DROPPED_MSGS.split("\n");
f.fixes = f.fixes.filter(fix => !droppedMsgs.some(msg => msg.includes(fix.id)));
'
Example (drift-aware desired-set update):
# prev_desired = what you previously intended *before* drift
# current = actually requested now
# reviewed = who already submitted a review
# Exclude manual dismissals: reviewers in prev_desired but not in current and not in reviewed.
drift=$(jq -cn --argjson p "$prev_desired" --argjson c "$current" --argjson r "$reviewed" '$p - $c - $r')
desired=$(jq -cn --argjson d "$desired" --argjson drift "$drift" '$d - $drift | sort')
# IMPORTANT: write marker using pre-drift desired, not the post-drift one.
marker_body="${marker} {\"desired\":$pre_drift_desired} -->"
Operational rule: if a matching/reconciliation step can plausibly pick the wrong entity due to wording, ordering, or manual UI actions, treat that as an algorithmic correctness failure—tighten inputs (IDs/markers), and tighten set logic (invariants + drift).
Define a single “success contract” for each step: only report ok/success if the operation is actually accepted; for optional steps, convert failures into a structured soft-skip (but still record a diagnostic reason).
Apply these rules: 1) Optional work ⇒ soft-skip with reason
2) Required work ⇒ hard-fail
3) API writes ⇒ treat provider error channels as failures
userErrors), treat non-empty as a failure even if the HTTP/transport succeeded.Example (optional step soft-skip)
async function stageBrowser({ hasNode, skipReasonRef, SkipChromium }) {
if (!hasNode) {
skipReasonRef.value = 'Node.js unavailable; optional browser tooling skipped';
return { skipped: true };
}
try {
await InstallAgentBrowser({ SkipChromium });
return { skipped: false };
} catch (e) {
skipReasonRef.value = `agent-browser install failed: ${String(e?.message || e)}`;
// Do NOT rethrow: optional degradation
return { skipped: true };
}
}
Example (GraphQL mutation userErrors)
async function applyMutationOrFail(client, mutation, variables) {
const data = await gql(client, mutation, variables);
const result = data?.[/* mutation root field */] || data;
const userErrors = result?.userErrors || [];
if (userErrors.length) {
throw new Error(`Mutation rejected by API: ${JSON.stringify(userErrors)}`);
}
// Optionally verify returned fields match the approved inputs here.
return result;
}
Outcome: fewer false “ok:true” results, predictable graceful degradation for optional features, and consistent diagnostics when failures happen.
Prevent inconsistencies between configuration sources of truth (build config, extension manifests, and package metadata) that cause IDE/runtime surprises.
Apply these rules when adding/updating any package/extension:
1) Mirror required build configuration options across comparable packages
Example (tsconfig.json):
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"declarationMap": true,
"outDir": "dist",
"rootDir": "src"
}
}
2) Make manifest tool exposure explicit
includeTools) so trial/managed paths can’t accidentally expose more than intended later.3) Declare or clearly document required env/config
QWEN_EXTERNAL_CONTEXT_CONFIG), surface that requirement in the extension manifest and/or the trial instructions so failures are actionable.4) Keep version sources in sync
package-lock.json and the workspace package.json versions agree (either bump the package.json or revert the lockfile entry) so the next npm install doesn’t silently rewrite lock state.Net effect: consistent IDE navigation, predictable runtime behavior, and fewer “it works on my machine”/dirty lockfile/version drift issues.
Documentation and doc-driven instructions must stay truthful and self-consistent with the underlying code and the document’s structure.
Apply this checklist when writing or editing docs/specs/templates:
Example pattern (robust cross-reference):
When handling null/undefined, be explicit about intent:
undefined, ensure ?? falls back to the intended “truth” (not a stale previous value).ReactNode variants in a way that changes semantics between render modes (inline vs overflow). If separators/text are part of the host contract, preserve them intentionally.null: for union/enum switches, use an exhaustive pattern so new members don’t silently fall through to null.false (not undefined).Example (routing fallback):
const reportedWorkspaceCwd = connection.sessionId
? connection.workspaceCwd
: (selectedWorkspaceCwd ?? primaryWorkspaceCwd);
// If selectedWorkspaceCwd is undefined, fall back to primaryWorkspaceCwd—not a stale connection.workspaceCwd.
Example (exhaustive switch):
switch (checks) {
case 'passing': return ...;
case 'failing': return ...;
case 'none': return null;
default: {
const _exhaustive: never = checks;
return null;
}
}
Example (test nullability):
expect(latestChatEditorProps.disabled).toBe(false); // not undefined
Any UI/logic that performs async work must be resilient to rapid user actions and intermediate async states: prevent re-entry, ensure callbacks use the latest intended state, and avoid losing results/errors when components unmount.
Apply these rules: 1) Guard against re-entry in async handlers
disabled, since Enter/keyboard can bypass button disabling before re-render).const submit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (saving || reloading) return; // prevent duplicate onEnter/rapid submit
setSaving(true);
try {
await onSave(/*...*/);
} finally {
setSaving(false);
}
};
2) Prevent concurrent requests
3) Make timing/streaming callbacks use “latest” state, and verify with tests
4) Be lifecycle-safe for in-flight operations
5) Handle “connecting/pending” phases deterministically
This standard targets the real failure modes described: stale/incorrect final results from scheduled callbacks, duplicated async calls (and conflicting revisions), lost errors due to unmount during pending work, and dropped actions when release happens before the underlying connection is ready.
When CI/CD builds and release automation publish or test packages from a monorepo, inter-workspace dependency specs and lockfile contents must stay publish-safe and CI-consistent.
Standards 1) No unresolvable workspace paths in published deps
"file:../..." specifiers in package.json of packages intended for registry publication; they can break npm i for consumers.2) Use publish-time-resolved specs
workspace:* so the dependency resolves to the correct concrete version at publish time.3) Keep lockfile aligned with manifests
package.json dependencies must be followed by lockfile reconciliation; stale/phantom entries in package-lock.json can cause unexpected CI lock-diff failures.4) If CI starts running new workspaces, ensure reporting is wired
Example (recommended inter-workspace dependency style)
{
"dependencies": {
"@qwen-code/channel-base": "workspace:*"
}
}
Operational checklist for PRs affecting release/CI
file: in published package manifests).workspace:* or ensure your versioning/release scripts rewrite dependency ranges.package-lock.json after dependency changes.When introducing or changing configuration options, treat the canonical config defaults and override policy as the single source of truth across runtime and provisioning.
Apply this standard:
1) Register every new (or newly-documented) key in the canonical DEFAULT_CONFIG used by the loader—do not rely on *.example files to define runtime behavior.
2) Verify merge semantics with regression tests:
DEFAULT_CONFIG.config.yaml must survive the merge unchanged.
3) Keep cli-config.yaml.example (and any public docs/comments) synchronized with DEFAULT_CONFIG.
4) For any install/build/enablement logic (e.g., installing optional toolsets), consult the same final user override mechanism used at runtime (e.g., agent.disabled_toolsets) and “soft-skip” consistently rather than reinstalling disabled components.Minimal pattern for (1)-(2):
# hermes_cli/config.py
DEFAULT_CONFIG = {
"agent": {
"claude_agent_sdk": {
"streaming": False,
"allow_metered_key": False,
"append_file": "",
},
},
}
# tests should assert:
# - deep-merge fills missing blocks/keys from DEFAULT_CONFIG
# - explicit user values in config.yaml remain unchanged
# - loader output matches canonical defaults exactly
For (4), ensure provisioning stages mirror runtime policy (e.g., read disabled toolsets from the existing config.yaml and skip the install step with a clear skipped reason when the toolset is disabled).
When your code depends on GitHub (or other remote) APIs, pagination and per-item mutations are often the dominant performance cost. Structure workflows/scripts to avoid redundant full scans and to prevent N+1 API patterns unless the workload is provably small.
Apply this standard:
gh api --paginate.Example pattern (avoid re-paginating; pass comment_id forward):
- name: Post status comment
id: post_status
if: ${{ always() }}
run: |
set -euo pipefail
MARKER='<!-- autofix-status -->'
# Locate or create status comment, then output its id
STATUS_ID=$(gh api "repos/${REPO}/issues/${PR}/comments" --paginate \
| jq -rs --arg m "$MARKER" --arg ab "$AUTOFIX_BOT" \
'[.[][] | select((.user.login // "") == $ab) | select((.body // "") | contains($m))] | last | .id // empty')
if [[ -z "$STATUS_ID" ]]; then
STATUS_ID=$(gh api "repos/${REPO}/issues/${PR}/comments" -f body="..." --jq '.id')
else
gh api --method PATCH "repos/${REPO}/issues/comments/${STATUS_ID}" -f body="..." >/dev/null
fi
echo "comment_id=$STATUS_ID" >> "$GITHUB_OUTPUT"
- name: Finalize
if: ${{ always() }}
run: |
set -euo pipefail
STATUS_ID='${{ steps.post_status.outputs.comment_id }}'
# Use STATUS_ID directly; do NOT re-run --paginate here.
echo "Using status comment id: $STATUS_ID"
This reduces execution time, API usage, and flakiness from rate limits—especially across repeated rounds or high-comment PRs.
Ensure workflow configuration (env vars, inputs, config lists) has a single authoritative definition and a clearly documented consumer.
Apply this when editing GitHub Actions/workflow configs or config-driven automation:
env: and step env:) unless the override is intentional and documented. Prefer keeping the setting only where it’s consumed.Example (pattern): derive the maintainer list once and reuse it, instead of duplicating:
- name: Classify
id: classify
run: |
# router outputs JSON including full maintainer list
result="$(node router.mjs ... )"
echo "maintainers=$(echo "$result" | jq -c '.maintainers')" >> "$GITHUB_OUTPUT"
- name: Apply review requests
env:
MAINTAINERS: '${{ steps.classify.outputs.maintainers }}'
run: |
# use MAINTAINERS as the single source of truth
node apply.mjs --maintainers "$MAINTAINERS"
This prevents drift, makes changes predictable, and avoids confusing behavior caused by precedence/overrides or unused settings.
Declarative API/provider configurations must be internally consistent with (a) the canonical identifiers used by the model registry/discovery layer and (b) the request-building logic that actually emits fields for the selected engine/path. This prevents mismatches, silent capability drops, and confusing “it’s configured but doesn’t work” behavior.
Apply these checks when adding/updating provider JSON: 1) Canonicalize model IDs
2) Make capability flags truthful
Example pattern (canonical ID + truthful capability):
{
"name": "example-provider",
"engine": "openai",
"api_key_env": "EXAMPLE_TOKEN",
"models": [
{
"name": "vendor/Canonical-Model-ID",
"context_limit": 123456,
"reasoning": true
/* reasoning is only true if the request builder emits the needed field for this model path */
}
]
}
If you’re unsure whether a capability is emitted for a given model/engine path, prefer “capability off” over a misleading on-flag, or implement the necessary request-layer support (with a clear, testable mapping).
When implementing set-based selection/reconciliation algorithms, ensure (1) deterministic outcomes and (2) invariant-preserving persisted state across runs.
A. Deterministic tie-breaking (order-independent “argmax”)
If you pick a “best” owner based on computed scores, explicitly define what happens when scores are equal—do not rely on Map/array iteration order.
function pickBestOwner(scores) {
let best = null;
let bestScore = -Infinity;
for (const [owner, score] of scores) {
if (score > bestScore) {
best = owner;
bestScore = score;
} else if (score === bestScore) {
// deterministic tie-break (example: lexical)
if (best === null || owner < best) best = owner;
}
}
return best;
}
B. Persist the canonical desired set (not a derived delta)
In multi-run reconciliation (markers/comments, requested reviewers, etc.), persisted state must represent the canonical target. If you persist a filtered/derived view (e.g., desired - reviewed), later runs can lose elements and permanently drift from the intended target.
// Canonical marker persistence: store full desired, not effectiveDesired.
const newMarkerBody = `${MARKER} {"desired":${JSON.stringify([...desired].sort())}} -->`;
Checklist for PRs in this area
When an action depends on daemon capabilities or other availability checks, never fail silently or hard-fail the whole UI. Instead: (1) gate capability-dependent parameters/requests so missing capabilities degrade gracefully, and (2) treat dependency outcomes as real failures—don’t return “handled/success” if the operation wasn’t actually performed; surface a user-visible toast/message.
Practical rules:
sourceType) that trigger requireCapability(...) if the capability is present; otherwise omit the parameter or use a fallback query.boolean/status (e.g., createSideTask()), check it. On false/unavailable, return a failure indicator consistent with the command flow and notify the user.Example (combined pattern):
if (directive.toLowerCase() === 'sider') {
const ok = createSideTask();
if (!ok) pushToast('warning', t('sideTask.unavailable'));
return true;
}
const listOpts: any = { /* ... */ };
if (hasCapability('session_source_metadata')) {
listOpts.sourceType = WEB_SHELL_SESSION_SOURCE_TYPE;
}
// If capability is missing, omit sourceType to prevent request-wide failure.
Treat every newly added user-facing string key as a documentation/UX contract for all supported locales.
When you add t() keys:
1) Classify the keys against the project’s translation policy (e.g., MUST_TRANSLATE_KEYS).
2) If the key is required: add translations in all required locale files in the same PR.
3) If the key is intentionally allowed to fall back (not in MUST_TRANSLATE_KEYS): don’t rely on “CI is green” silently—add an explicit maintainer note and create/track a follow-up “translation pass” issue (prioritize locales, define a quality gate, and link it in the PR).
4) Double-check the locales that are expected to be complete (e.g., full parity locales). Untranslated strings there should be fixed immediately.
This prevents users from seeing raw English fallback text (even though it won’t crash), while still supporting deliberate rollout decisions.
Example (process pattern):
// 1) Add new keys to the i18n source
export default {
'Set Default Model': 'Set Default Model',
// ...
}
// 2) In the PR description / follow-up tracking, state which case applies:
// - Required locales: <list> (translations added)
// - Optional fallback: <list> (link a follow-up translation pass)
// - Rationale: key intentionally excluded from MUST_TRANSLATE_KEYS
Rule of thumb: if users in a locale will see English instead of the intended language, the PR must either include the translations or explicitly schedule a translation pass with owners and scope.
Configuration docs/examples and runtime behavior must stay aligned, and configuration must be explicit and validated.
Apply two rules:
1) No silent no-ops: If a config field is accepted by schema/docs, it must actually affect runtime behavior—or be removed from examples and clearly documented as unused/ignored. Add validation/tests that cover example payloads to prevent “looks supported but isn’t” failures.
2) No ambiguous defaults: For critical targets derived from environment/remotes (repo selection, workspace selection, endpoints), do not guess from generic names like origin. Require explicit config/flags (e.g., --repo owner/name) and validate structure (e.g., the remote URL must match the intended owner/repo). If missing/ambiguous, fail fast with a clear error or ask rather than continuing.
Example pattern:
// Ensure only the actually-used field controls behavior
const timeoutMs = config.autoRecall?.timeoutMs; // not config.timeoutMs
assertNumber(timeoutMs, 'autoRecall.timeoutMs is required');
// Ensure repo selection is explicit and validated
function pickRepo(requiredOwnerRepo: string, remotes: Record<string, string>) {
if (!requiredOwnerRepo) throw new Error('Provide --repo owner/name');
for (const url of Object.values(remotes)) {
if (urlIncludesOwnerRepo(url, requiredOwnerRepo)) return requiredOwnerRepo;
}
throw new Error('No remote matches the intended --repo owner/name');
}
Result: admins/users get predictable configuration behavior, and tooling won’t act on the wrong repo or silently ignore intended settings.
Sensitive authentication tokens must not remain in the browser URL after they are consumed. Tokens in query parameters (?token=) will leak via browser history, server access logs, and Referer headers when users navigate away; removing URL fragments alone is insufficient if ?token= is supported.
Apply this standard by:
sessionStorage) or internal state for refresh/reload behavior.#fragment).Example pattern:
function replaceStandaloneSessionUrl(url: URL) {
// ... logic that extracts token from url.searchParams
// After token is consumed, remove it from the address bar
if (!import.meta.env.DEV) {
url.searchParams.delete('token');
url.searchParams.delete('daemon');
}
// ... continue with navigation/state update
}
In performance-sensitive hot paths, ensure you (1) don’t repeat expensive work, (2) keep async/event-loop paths non-blocking, (3) bound external operations with finite timeouts, and (4) avoid unnecessary computation/materialization by prefiltering queries and projecting only what’s needed.
Practical rules:
Example pattern (reused probe + bounded subprocess):
async def send_audio(path, upload_fn, send_msg_fn, ffprobe_fn):
# Probe once (prefer an async-friendly ffprobe wrapper if available)
duration_ms = await ffprobe_fn(path, timeout=10.0) # must be bounded
# Upload using the same duration metadata
media_id = await upload_fn(path, metadata={"duration_ms": duration_ms})
# Reuse for message payload (no second probe)
return await send_msg_fn(media_id, metadata={"duration_ms": duration_ms})
Checklist to apply during review:
When handling failures, ensure you (a) don’t lose the real root cause, (b) never introduce new exceptions while trying to report one, and (c) keep graceful degradation both implemented and tested.
Apply these rules:
spawnSync/execSync): if result.error exists, log it and return/exit predictably; don’t infer a transport failure from empty stdout.catch (e.g., let lastError; ... catch (e) { lastError = e; }).new Error(message, { cause: lastError }) so stacks/types aren’t discarded.deadlineError() helper) to keep error formatting consistent.always()), include fallback guards (e.g., || echo "...continuing.") and assert them in tests.Example pattern (scope-safe + preserve cause):
function deadlineError(lastError) {
return new Error(
`Model generation time budget exhausted: ${lastError?.message ?? 'unknown error'}`,
{ cause: lastError },
);
}
let lastError;
for (;;) {
if (Date.now() >= deadline) throw deadlineError(lastError);
try {
// ...
} catch (e) {
lastError = e;
// retry / backoff
}
}
Checklist for review:
1) Are all error sources checked (not just stdout/text)?
2) Can any error-reporting path throw a new exception (scope/ReferenceError)?
3) Do wrapped errors include { cause }?
4) Are control-flow decisions based on stable identifiers (constants), not rewordable strings?
5) Are fallback/best-effort behaviors covered by assertions in tests?
6) Is error-message construction centralized to avoid drift?
When transforming, sorting, deduplicating, or merging structured data, ensure comparisons use domain-correct semantics and identity signals are preserved.
Apply these rules:
1) Parse before comparing/sorting. Convert timestamp/typed fields into domain types (e.g., RFC3339 → instant) rather than relying on raw string/lexical order. When values may be missing/unparseable, still produce deterministic output with an explicit tie-breaker.
2) Canonicalize keys used for dedup/join. If two inputs can represent the same logical entity via different encodings (paths with ../symlinks, dot vs bracket notation, root vs nested identifiers), normalize them before using them in a HashSet/map key.
3) Keep boundary/identity predicates strict for merges. If you relax equality checks that define a boundary (e.g., “which turn does this reasoning belong to?”), you can merge distinct events. If recovery requires tolerance, restrict it to the smallest safe dimension and guard ambiguity (e.g., redacted placeholders).
4) Precedence matters. In pipelines with multiple enrichment/inference paths, run authoritative sources before inference, so guards like “only fill when unset” don’t block correct data.
5) Lock with regression tests around pathological inputs (missing dates, mixed offsets, ambiguous redaction, structured key syntax variants).
Example pattern (semantic sort with deterministic fallback):
let mut items: Vec<(String, String)> = arr
.iter()
.filter_map(|m| {
let id = m.get("id")?.as_str()?.to_string();
let created_at = m.get("created_at")
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();
Some((id, created_at))
})
.collect();
// Prefer sorting by parsed instant; fall back deterministically.
items.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
Checklist for PRs in this area:
When handling failures in async, remote, or multi-step flows, make the system degrade safely and keep UI/state consistent with what the server actually persisted.
Apply these rules:
1) Bound remote calls; fall back on hang
2) Keep optimistic updates reversible and server-aligned
3) Guard destructive operations with preconditions
4) Retry best-effort operations with bounded backoff and clear completion semantics
Example pattern (timeout + fallback + consistent state + bounded retry):
async function withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
return await Promise.race([
p,
new Promise<T>((_, reject) => setTimeout(() => reject(new Error('timeout')), ms)),
]);
}
async function listModelsWithFallback(providerId: string): Promise<string[]> {
try {
const live = await withTimeout(
fetchLiveModels(providerId), // remote call
4000
);
return live;
} catch {
return await fetchCachedInventoryModels(providerId); // safe degraded path
}
}
async function retryEachUri(uris: string[], fn: (uri: string) => Promise<void>) {
const maxAttempts = 3;
for (const uri of uris) {
let attempt = 0;
while (attempt < maxAttempts) {
try {
await fn(uri);
break; // success for this item
} catch {
attempt++;
if (attempt >= maxAttempts) throw new Error(`exhausted: ${uri}`);
const backoffMs = Math.min(200 * 2 ** (attempt - 1), 2000);
await new Promise((r) => setTimeout(r, backoffMs));
}
}
}
}
If you follow these principles together, your error handling will be both user-friendly (no hangs), correct (no state divergence), and resilient (retries are bounded and semantics are explicit).
When implementing algorithms that merge incremental updates and compute ordering (grouping/sorting), ensure the algorithm matches the producer semantics and uses semantically correct keys—don’t rely on heuristic fixes.
Apply these rules:
1) Incremental merge semantics: if the upstream emits append-only deltas, merge with append (e.g., +=). If chunks are cumulative, only then use overwrites or dedup logic.
2) Sorting/grouping keys: sort by the timestamp that represents the meaningful event (e.g., “last message activity”), not by generic updatedAt that may change for renames/metadata-only updates.
3) Live/remote dependencies: if the input set is built via remote discovery, bound per-provider latency and fall back to a stable cache to prevent the whole computation from stalling.
Example patterns (adapted):
// 1) Append-only delta merge (don’t use dedup/overlap heuristics)
function mergeTextDelta(existing: string, incomingChunk: string) {
return existing + incomingChunk;
}
// 2) Semantically correct sort key
const tA = new Date(a.lastMessageAt ?? a.updatedAt).getTime();
const tB = new Date(b.lastMessageAt ?? b.updatedAt).getTime();
projectSessions.sort((a, b) => tB - tA);
// 3) Bounded live discovery with fallback
async function withTimeout<T>(p: Promise<T>, ms: number): Promise<T> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);
p.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });
});
}
async function getModelsWithFallback(live: () => Promise<string[]>, cache: string[], ms = 4000) {
try {
return await withTimeout(live(), ms);
} catch {
return cache;
}
}
This prevents subtle UI/state bugs caused by incorrect merge assumptions, wrong sort keys, and unbounded remote computation.
Whenever you change feature extras or dependency constraints in config (e.g., pyproject.toml), apply the same compatible version range everywhere that dependency is installed or resolved, and follow the dependency policy: bounded ranges only (no bare lower bounds; no conflicting exact pins). Regenerate the lockfile after the update.
Checklist
numpy<2, ensure the same constraint is used in any sibling/lazy dependency table or gateway installer logic.>=0.1.1,<0.3), not exact pins like ==0.1.1, and avoid declarations that only specify a lower bound (e.g., pkg>=1.2 without an upper bound).uv.lock so the resolved graph matches what CI/users install.Example (pattern)
# pyproject.toml
[project.optional-dependencies]
voice = [
"numpy<2",
]
tenki = [
"tenki>=0.5.1,<0.7",
]
native-fetch = [
"readability-lxml>=0.8,<0.9",
"html2text>=2024.0,<2025.0",
]
Then update any other install mechanism that still references the old pins/ranges, and run uv lock (or the repo’s standard lock regeneration step) so uv.lock reflects the same bounds.
When configuration affects scripts (env vars, dotenv files, compatibility gates), treat it as serialized input/output and enforce correctness at three points: (1) safe encoding, (2) correct source scoping, and (3) declared bounds.
Apply this standard: 1) Escape/quote values you write into dotenv/shell syntax.
KEY="value", ensure the value has embedded \ and " escaped so the generated line remains valid.# value may contain backslashes and quotes; escape for a double-quoted dotenv token
escaped="$value"
escaped=$(printf '%s' "$escaped" | sed 's/\\/\\\\/g; s/"/\\"/g')
echo "KEY=\"$escaped\"" # always double-quote the serialized token
2) Scope config-file reads to the explicit boundary variable.
HERMES_ENV_FILE, only read the token(s) from that file.HERMES_HOME (or similar) is set.3) Enforce compatibility ranges exactly as declared.
requires-python), bound your “>=” checks to that range; don’t assume a broader interpreter is usable.<3.14).Net effect: generated config remains parseable, scripts read the intended configuration source, and installations/feature gates behave consistently with the project’s declared support.
Security-sensitive data and sinks must be hardened before use. Concretely:
1) Auth/token validity guarantees
getAuth) so all call sites benefit, using a refresh threshold that matches real provider behavior (e.g., provider-specific skew rather than a one-size-fits-all 30 minutes).2) Sanitize strings embedded into terminal escape sequences
\x00-\x1f and \x7f).3) Use secure, permissioned temp locations
0700).tmpdir() unless you can enforce the same security model.Example (sanitizing OSC 8 link URLs):
function stripControlChars(s: string): string {
return s.replace(/[\x00-\x1f\x7f]/g, "");
}
const href = stripControlChars(token.href ?? "");
const osc8Open = `\x1b]8;;${href}\x07`;
const osc8Close = `\x1b]8;;\x07`;
When selecting a “preferred” item (via find, filter, pagination anchors, etc.) or deciding based on a computed threshold, ensure two things:
1) Compare like with like: normalize/parse inputs so the keys you compare are in the same canonical form.
2) Use explicit priority + fallback: run a primary search first; only if it yields nothing should you consult a fallback source. Avoid making fallback evidence primary.
Practical checklist:
authType:modelId), always decode/resolve to the same shape before comparing to stored objects.Code pattern (key normalization + prioritized fallback):
// 1) Normalize first (so comparisons match)
const normalized = isCompactionMode
? resolveModelId(settings?.merged?.compactionModel?.trim() ?? '')
: undefined;
// 2) Primary then fallback
const preferred = (() => {
// primary: use the most reliable/expected source(s)
const primary = normalized
? availableModelEntries.find(({ authType, model }) =>
authType &&
authType === normalized.authType &&
model.id === normalized.modelId
)
: undefined;
if (primary) return primary;
// fallback: weaker/secondary match only if primary failed
return availableModelEntries.find(({ model }) => model.id === normalized?.modelId);
})();
Apply this same approach to anchor selection and transcript pagination: prefer session_update-derived ids first; only if absent should you use the history_truncated marker id.
For any async workflow that fans out (e.g., Promise.all over providers) or mutates shared session state, apply two rules: 1) Bound/cancel all external async work (timeouts must abort the underlying operation, not only the awaiting caller). 2) Centralize lifecycle transitions for shared mutable state (prefer a state enum + transition helper over ad-hoc “reset fields in parallel”).
How to apply
Example (client-side timeout with defense-in-depth)
const LIVE_MODELS_TIMEOUT_MS = 4000;
function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T> {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
promise.then(
(value) => { clearTimeout(timer); resolve(value); },
(err) => { clearTimeout(timer); reject(err); }
);
});
}
// In fan-out code, ensure each task is bounded so Promise.all can complete.
const liveIds = await withTimeout(
acpListProviderSupportedModels(providerId),
LIVE_MODELS_TIMEOUT_MS,
`live model discovery for ${providerId}`
);
Example (lifecycle state centralized)
enum PromptLifecycle { Idle, AwaitingRun, Running, Succeeded, Failed }
function transitionEntry(entry: Entry, next: PromptLifecycle) {
// Reset/updates happen in one place to keep concurrent transitions consistent.
switch (next) {
case PromptLifecycle.Idle:
entry.activePromptAttemptId = null;
entry.activeRunId = null;
return;
// other states...
}
}
This prevents: (a) UI workflows stalling indefinitely due to a single slow dependency, (b) leaked in-flight work when only the client await is timed out, and (c) inconsistent session state caused by partial or parallel field resets.
When adding or updating test/verification logic, treat the harness setup as part of the test and ensure the evidence is causally attributable and non-vacuous.
Standard
node_modules, document and enforce when that’s a clean control. If dependency inputs change (e.g., package.json/lockfiles), either run a dependency-aware control or explicitly record the confound.realpath of resolved modules) and gate pass/fail of the verification on that.startswith, and you filter by bot author). Also ensure ids are re-resolved at patch time when threads/comments may have mixed order.Example pattern (monorepo control isolation)
# Run from the base worktree.
# 1) Resolve what the code under test actually loads.
REALPATH=$(node -p "require('fs').realpathSync(require.resolve('@qwen-code/qwen-code-core'))")
# 2) Assert it points into the base tree (pseudo-check).
case "$REALPATH" in
*tmp/base-tree/*) echo "OK wiring: $REALPATH" ;;
*) echo "FAIL: base control resolved to non-base code: $REALPATH" ; exit 1 ;;
esac
Example pattern (non-vacuity rule)
Example pattern (harness regression tests)
startswith (not contains) and filters by bot login, so a future edit can’t silently reintroduce clobbering behavior.Design GitHub Actions concurrency so overlapping runs can’t corrupt multi-step outcomes.
Rules:
1) Don’t assume concurrency is a durable multi-stage queue. If stage A and stage B must be serialized as one logical transaction, either:
2) Align the concurrency group predicate with the job if gate. GitHub evaluates concurrency before job if, so any kill-switch/feature flag that changes run behavior must be included in the concurrency group condition too.
3) Prevent “request accepted, nothing happens”. When concurrency saturation can drop jobs (only one running + one pending), add an always-hosted acknowledgement path (e.g., in authorize) that posts a visible “queued/dropped” notice based on in-flight counts.
4) Make publication overwrite-safe:
Example patterns:
A) Same-boundary serialization across dependent stages (use when B must not overlap A):
jobs:
verify:
concurrency:
group: ${{ format('{0}-verify-{1}', github.workflow, github.event.issue.number) }}
cancel-in-progress: false
publish-verify:
needs: [verify]
concurrency:
group: ${{ format('{0}-verify-{1}', github.workflow, github.event.issue.number) }}
cancel-in-progress: false
B) Per-run isolation + idempotent publication (use when concurrency can’t be made durable):
jobs:
verify:
concurrency:
group: ${{ format('{0}-verify-run-{1}', github.workflow, github.run_id) }}
cancel-in-progress: false
publish-verify:
needs: [verify]
concurrency:
group: ${{ format('{0}-verify-run-{1}', github.workflow, github.run_id) }}
cancel-in-progress: false
C) Include kill-switch/qualifiers in both if and concurrency.group (conceptually):
if: vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true' changes executability,group: expression so the same PR doesn’t share groups across modes.If you apply these principles, your concurrency design becomes correct under race conditions, feature toggles, and saturation—without relying on brittle scheduling assumptions.
Security gates and cleanup must be fail-closed and boundary-proven.
Apply these rules when implementing/adjusting secure workflows:
1) Authorization must not degrade
2) Re-sweep after PR-controlled lifecycle scripts
npm ci/build (or any PR-controlled lifecycle hooks), assume they may plant artifacts into runner temp/upload staging.rm -rf then mkdir -p in the same step, and keep ordering stable (rm → mkdir → proxy/agent).3) Prove the auth boundary with real requests
Authorization header → 4014) Make security tests hermetic (no global/system config influence)
GIT_CONFIG_GLOBAL=/dev/null and GIT_CONFIG_SYSTEM=/dev/null).core.hooksPath) so failures can’t be masked by developer machines.Example (authorization routing + fail-closed execution):
# In the shell gate script
body_lc="${COMMENT_BODY,,}"
case "$body_lc" in
*@qwen-code /verify*)
# FAIL CLOSED: require BOTH principals to have permission
# (e.g., should_run=false unless author_has_write && commenter_has_write)
;;
*@qwen-code /tmux*)
# Keep existing narrower gate
;;
*)
should_run=false
;;
esac
Example (post-PR lifecycle hygiene):
# In the agent step, immediately before upload/agent start
rm -rf "$RUNNER_TEMP/verify-results"
mkdir -p "$RUNNER_TEMP/verify-results"
start_openai_proxy
Make UI behavior robust to failure scenarios by aligning (a) what you validate, (b) what you treat as success, and (c) how state is updated when partial failures happen.
Apply these rules: 1) Don’t treat async work as successful until it resolves. Show success toasts only after awaiting; catch and handle rejections. 2) Avoid brittle callback chains when operations aren’t atomic. Prefer authoritative, event-driven state updates that carry enough context to remain consistent under partial failure. 3) Prevent “hidden required field” failures by gating submit and validating only the inputs that are actually rendered/required.
Example pattern:
// 1) Async success after await
const handleCopyMarkdown = async () => {
try {
const markdown = conversationToMarkdown(messages, session?.name);
await navigator.clipboard.writeText(markdown);
toast.success(intl.formatMessage(i18n.copiedMarkdown));
} catch {
toast.error(intl.formatMessage(i18n.copyFailed));
}
};
// 2) Gate actions to avoid hidden required-field failures
const requiredNonOAuthKeys = /* compute required keys that are rendered */;
const canSubmit = hasOAuth ? requiredNonOAuthKeys.length > 0 : true;
// render footer only when canSubmit, and validate only those keys
const handleSubmitForm = () => validateAndSubmit(requiredNonOAuthKeys);
// 3) For multi-step updates, prefer authoritative event/state updates
// rather than relying on an 'onComplete' callback that may not fire
// when step N succeeds and step N+1 fails.
// e.g., update header from a full 'config_option_update' payload.
When a cache is invalidated asynchronously, ensure coherence between (a) the invalidation/version signal and (b) the cached payload/derived artifacts.
Standard
(version, tools)). Never let callers read the version from one moment and the payload from another.(version, payload)—preferably in the same logical iteration/turn, not “some time later”.Illustrative pattern (Rust-like)
// Cache stores version + payload together.
struct Cache<T> {
inner: Option<(u64, T)>,
}
impl<T> Cache<T> {
async fn get(&mut self, version: &AtomicU64, fetch: impl FnOnce() -> T) -> (u64, T) {
if let Some((v, data)) = self.inner.as_ref().cloned() {
return (v, data);
}
let v = version.load(Ordering::SeqCst);
let data = fetch();
self.inner = Some((v, data.clone()));
(v, data)
}
async fn invalidate_and_bump(&mut self, version: &AtomicU64) {
// Hold the lock for both operations.
self.inner = None;
version.fetch_add(1, Ordering::SeqCst);
}
}
// Reply loop: baseline comes from the payload it used.
let (baseline_version, tools) = tools_cache.get(...).await;
// ... build prompts using `tools` ...
if extension_manager.tools_cache_version() != baseline_version {
let (new_version, new_tools) = tools_cache.get(...).await;
// Rebuild prompts derived from `new_tools`.
}
Why
Adopting this standard prevents whole classes of intermittent “cache changed mid-use” bugs and makes refresh behavior deterministic under concurrency.
When implementing string operations that depend on the environment (terminal/UI rendering or filesystem paths), avoid naive .length/single-separator logic. Use algorithms that are correct for Unicode/code points and for the actual width/splitting rules of the runtime.
Apply:
/ and \ (after trimming trailing separators), so Windows and POSIX paths behave the same.Example patterns:
// Width-safe truncation (prefer established libs)
import stringWidth from 'string-width';
import cliTruncate from 'cli-truncate';
function truncateForTerminal(label: string, maxCells: number) {
// Truncates by terminal cells; avoids naive .length truncation.
// (Use/align with the same render-side truncation approach.)
return cliTruncate(label, maxCells, { ellipsis: '…' });
}
// Cross-platform path splitting
function splitDirPath(dir: string): { name: string; parent: string } {
const trimmed = dir.replace(/[\\/]+$/, '');
const parts = trimmed.split(/[\\/]/);
const name = parts.pop() ?? '';
const parent = parts.join('/');
return { name, parent };
}
Checklist:
.length to decide visual fit in terminal/UI.When handling optional/missing inputs, normalize and guard early so “missing” can’t accidentally become a real value or clobber existing state.
Rules:
None immediately (e.g., treat Some(0)/""/placeholder numbers as “unset”), before applying fallback chains or “is set?” logic.Example (Rust):
fn apply_update(existing: &mut Config, input: &Input) -> anyhow::Result<()> {
// 1) Normalize “not configured” sentinel -> None
let new_limit: Option<usize> = match input.context_limit {
Some(0) | None => None,
Some(v) => Some(v),
};
// 2) Preserve unspecified fields (partial update)
if let Some(limit) = new_limit {
existing.context_limit = Some(limit);
}
if let Some(new_provider) = input.provider.as_deref() {
if !new_provider.is_empty() {
existing.provider = new_provider.to_string();
}
}
// 3) Guard on prerequisites (defer/return)
if existing.working_dir_missing() {
anyhow::bail!("working_dir_missing");
}
Ok(())
}
Use this pattern consistently across null/optional fields, sentinels, and partial request bodies to avoid meaning drift and state poisoning.
Always handle nullable/optional state explicitly before executing logic that can mutate state, clear user input, or drop data. Use early returns or dedicated “disabled” props driven by well-defined nullable/flag conditions, and preserve intentional empty values instead of treating all falsy/empty inputs as “missing.”
How to apply:
Example pattern:
function onUpdate({ currentSnapshot, updateMessage }: any) {
// Explicit null/flag guard
if (!currentSnapshot?.session || currentSnapshot.session.working_dir_missing === true) {
return; // block side effects when required data is missing
}
updateMessage();
}
function stripEmptySlots(params: Record<string, any>) {
for (const [key, value] of Object.entries(params)) {
const isEmptyObject =
value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0;
if (isEmptyObject) delete params[key];
// Note: empty arrays are preserved
}
}
Ensure every place that stores, looks up, validates, or returns provider/model/function identifiers uses a clear internal naming contract:
-latest, -0709, or Bedrock -vN(:M)? resolve to the same canonical entry).*_PROVIDER_NAME (and other naming constants) over hard-coded provider strings.Example (disambiguated picker label pattern):
// Build rows that always map back uniquely.
let mut entries: Vec<(String, String, String)> = vec![]; // (label, provider_name, model_id)
for (meta, _ptype) in &all {
for m in models_for_meta {
let mut label = format!("{} ▸ {}", meta.display_name, m);
// Ensure uniqueness even if display_name + model collide across providers.
if collides_somehow {
label.push_str(&format!(" (provider:{})", meta.name));
}
entries.push((label, meta.name.clone(), m));
}
}
Apply these rules anywhere you normalize model/provider identifiers or convert between internal ids and user-facing names, so naming stays consistent, lookups remain correct, and selections can’t mis-route.
When changing CI routing/guardrails (workflows, CODEOWNERS, rulesets), ensure the policy intent is still enforced in the same way.
Standard
1) Never replace enforced approvals with “request reviewers”: reviewer requests do not block merges. If your repo relies on require_code_owner_review: true, keep CODEOWNERS entries (or explicitly update the ruleset) rather than assuming the workflow will gate merges.
2) Eliminate config drift: any canonical routing list (e.g., maintainer allow/skip lists used by scripts) must not be duplicated across script + workflow YAML without a sync check.
3) Ensure routing logic is tested in CI: if a test file exists but is not included in the workflow’s test selection list, CI coverage is illusory—add it to the workflow selector.
Practical implementation
Example (workflow/YAML config sync test pattern)
import fs from 'node:fs';
import yaml from 'js-yaml';
// Canonical list lives in one place (e.g., imported from the routing script)
const MAINTAINERS = ['wenshao', 'tanzhenxin', 'yiliang114', 'LaZzyMan'];
const workflow = fs.readFileSync('.github/workflows/ci.yml', 'utf8');
const doc = yaml.load(workflow);
// TODO: locate the step/yaml expression that defines the maintainer skip-list
// and extract it into `skipList` deterministically.
const skipList = /* parse from doc */ [];
if (JSON.stringify(skipList.sort()) !== JSON.stringify([...MAINTAINERS].sort())) {
throw new Error('CI workflow maintainer skip-list is out of sync with canonical MAINTAINERS');
}
Checklist before merging changes to routing/guardrails
Make null/undefined (and “invalid/unknown”) states explicit and prevent them from flowing into non-null/non-optional operations.
Apply these rules:
1) Enforce compiler null safety: enable strictNullChecks so the typechecker blocks x?.foo()/x.foo() on string | null-like values.
2) Guard before method calls: if a value can be null/undefined, check it before calling string/array methods.
3) Align conversion boundaries: parsing/normalization that accepts unknown must either:
?? default, ensure undefined (missing support) and false (explicitly disabled) are treated differently.Example (null guard + explicit fallback):
function getErrorPrefix(err: string | null | undefined) {
if (!err) return null; // handles ''/null/undefined per your policy
return err.startsWith('No API key found') ? err : null;
}
const constrainedStrict = supportsStrictMode
? resolveJsonSchemaStrictSampling(tool, true)
: undefined; // explicit
const strict = constrainedStrict ?? defaultStrict; // only applies when constrainedStrict is undefined
This prevents unsafe member access, accidental propagation of undefined/invalid values across typed boundaries, and confusing fallback behavior.
When unit tests depend on filename/path classification via regex (e.g., routing maintainers, detecting test files), add explicit test cases that exercise every alternation token and mapping entry in the regex/table. Uncovered alternations can fail silently if someone introduces a typo or refactors part of the pattern.
Apply this by:
...|...|..., create at least one classify([...]) test per branch (e.g., .test., .spec., __tests__, .test-utils.).a|b|c), add a test that targets a path matching that exact alternation.Example (illustrative unit tests):
it('treats .spec. as test-only', () => {
const result = classify(['packages/core/src/tools/grep.spec.ts'], 'someone');
assert.equal(result.reviewers.length, 0);
assert.match(result.reason, /test-only/);
});
it('routes services compaction paths to the right domain expert', () => {
const result = classify(['packages/core/src/services/compactionService.ts'], 'someone');
assert.ok(result.reviewers.includes('LaZzyMan'));
});
When handling optional/nullable values in TypeScript/React, make “unset/default” distinct from “legitimate empty/zero” and avoid truthiness-based guards.
Apply: 1) Use a dedicated sentinel for “never set”
null/undefined to represent “unset”, especially when 0, '', or false are meaningful.
2) Check explicitly for sentinel/optionalsvalue !== undefined / value != null over if (value) when the value may be 0 or ''.
3) Normalize before branchingtrim) before deciding which code path applies.
4) Validate using the intended combined conditionExample (sentinel + explicit checks):
// Sentinel models “never set” separately from a real 0.
const [navExpandedWidth, setNavExpandedWidth] = useState<number | null>(null);
useEffect(() => {
window.electron.getSetting('navExpandedWidth').then((stored: number | null) => {
if (stored === null) {
// keep component default
return;
}
// stored === 0 is a legitimate explicit value, not “unset”
setNavExpandedWidth(stored);
});
}, []);
// Explicit optional check (don’t rely on truthiness)
const initialMessage = editedMessage !== undefined
? { msg: editedMessage, images: [] }
: undefined;
This prevents bugs where guards accidentally skip applying valid persisted values (e.g., 0) or mis-handle empty-but-present content (e.g., '').
In React components, make UI state transitions and DOM identity depend on the current rendered context (route/view/filter) and the current component instance. This prevents stale navigation, incorrect optimistic updates, and broken label/control associations.
Apply this as a rule of thumb:
id/htmlFor using useId().Example patterns:
// 1) Route-aware transition (concept)
function leaveRouteIfCurrent(currentId: string, nextPath = '/') {
if (getCurrentOpenSessionId() === currentId) navigate(nextPath);
}
// 2) Filter-aware optimistic update
const handleToggleArchive = async (session: SessionListItem) => {
const isArchived = !!session.archivedAt;
setSessions(prev => {
if (activeFilter === 'all') {
// keep row; it still matches
return prev.map(s => (s.id === session.id ? { ...s, archivedAt: isArchived ? null : new Date().toISOString() } : s));
}
// active/archived views: toggle may move it out of scope
return prev.filter(s => s.id !== session.id);
});
};
// 3) Instance-unique label/control pairing
function ParameterInputModal({ parameters }: { parameters: { key: string }[] }) {
const reactId = React.useId();
const fieldId = (key: string) => `${reactId}-${key}`;
return (
<div>
{parameters.map((param) => (
<div key={param.key}>
<label htmlFor={fieldId(param.key)}>{param.key}</label>
<input id={fieldId(param.key)} />
</div>
))}
</div>
);
}
Use this checklist whenever you change data that affects (1) what’s open on the screen, (2) what’s included in the current list/filter, or (3) how inputs are labeled/identified in the DOM.
Prefer designs that avoid unnecessary resource usage—especially filesystem churn and redundant persistence/reload.
setXXX patterns: don’t introduce redundant save()/reload cycles when a simple in-memory update (or the same approach used elsewhere) suffices.Example (OS temp dir for temporary work):
import { mkdtemp, rm } from "node:fs/promises";
import os from "node:os";
import { join } from "node:path";
// Use system temp root to avoid accumulating data under a home directory.
const tempRoot = await mkdtemp(join(os.tmpdir(), "agent-"));
try {
// ... write/edit temp files ...
} finally {
// Ensure cleanup even if OS doesn’t immediately collect.
await rm(tempRoot, { recursive: true, force: true });
}
Example (settings update pattern):
setXXX methods update this.settings/globalSettings directly without extra reload work, mirror that approach and avoid adding additional persistence/reload steps unless correctness requires it.When configuration can vary by user/environment, resolve it deterministically (following documented precedence), keep it configurable instead of hardcoded, and apply it dynamically if it may change at runtime.
Practical rules:
/settings), don’t decide behavior once during session creation—re-evaluate from the session settings manager when converting requests.Example (dynamic blockImages handling):
// Bad: captures blockImages once at session creation
// const convertToLlmWithBlockImages = blockImages ? filteredConvertToLlm : convertToLlm;
// Good: decide per-use from session manager
function makeConvertToLlm(sessionManager: { getBlockImages(): boolean }) {
return async function convertToLlm(...args: unknown[]) {
const shouldBlock = sessionManager.getBlockImages();
if (shouldBlock) return convertToLlmFilteredImages(...args);
return convertToLlmUnfilteredImages(...args);
};
}
Following this standard prevents stale configuration behavior, reduces deployment brittleness, and makes feature flags and user settings reliably predictable.
For any code that parses/normalizes strings or aggregates structured events, require deterministic, complete, and bounded logic:
Example (quote-aware normalization pattern):
export function normalizeNulRedirects(command: string): string {
if (process.platform !== "win32") return command;
let out = "";
let inSingle = false;
let inDouble = false;
for (let i = 0; i < command.length; i++) {
const ch = command[i];
if (ch === "'" && !inDouble) inSingle = !inSingle;
else if (ch === '"' && !inSingle) {
const escaped = (() => {
let bs = 0;
for (let k = i - 1; k >= 0 && command[k] === "\\"; k--) bs++;
return bs % 2 === 1;
})();
if (!escaped) inDouble = !inDouble;
}
out += ch;
// Only rewrite redirects when not inside quotes (bounded, deterministic)
// if (!inSingle && !inDouble && matchesNulRedirectAt(i, command)) { ... }
}
return out;
}
Apply the same standard to metrics aggregation: ensure guards don’t accidentally skip new contributors (e.g., treat any entry type with usage as a candidate for token/cost accumulation).
When code has multi-step lifecycle operations (spawn/register/sync/stop) or user/config-driven behavior, make failures explicit and recoverable: model the lifecycle with a small state machine, track which resources were acquired so teardown can always run safely in reverse, and degrade gracefully with validated fallbacks and user-visible diagnostics. Also keep retry/error event schemas unambiguous so monitoring and recovery logic can reliably interpret what happened.
Apply it like this:
error state reachable from any step.rpcProcess, sessionId, radiusId) separately; on any failure, run best-effort cleanup in reverse acquisition order.Example (pattern):
type State = 'starting' | 'online' | 'stopping' | 'stopped' | 'error';
class RpcLifecycle {
private state: State = 'stopped';
private acquired: {
rpcProcess?: { stop(): Promise<void> };
sessionId?: string;
radiusId?: string;
} = {};
async start() {
this.state = 'starting';
try {
// 1) acquire resources step-by-step
this.acquired.rpcProcess = await this.startRpc();
this.acquired.sessionId = await this.syncSession();
this.acquired.radiusId = await this.registerRadius();
this.state = 'online';
} catch (e) {
await this.cleanupBestEffort();
this.state = 'error';
throw e;
}
}
private async cleanupBestEffort() {
// reverse order of acquisition
if (this.acquired.radiusId) await this.unregisterRadiusBestEffort(this.acquired.radiusId);
if (this.acquired.sessionId) await this.unsyncSessionBestEffort(this.acquired.sessionId);
if (this.acquired.rpcProcess) await this.acquired.rpcProcess.stop().catch(() => {});
this.acquired = {};
}
}
Treat every identifier (tool name, command name, provider slug, theme name, thread key) as a runtime contract: you must generate, transform, and resolve it consistently, and preserve an unambiguous mapping between any emitted/sanitized UI value and the backend identity.
Apply these rules: 1) Use a single source-of-truth canonical form for comparisons/dispatch.
custom:).
2) Keep “display/sanitized” values separate from “dispatch” values.Example pattern (opaque UI token → canonical dispatch):
# UI: show truncated label, dispatch uses stable token
items = {token: canonical_name}
# When rendering select options
for token, canonical in list(items.items())[:24]:
select_option = discord.SelectOption(
label=canonical[:100], # display-only truncation
value=token, # dispatched identity
)
# On selection
token = interaction.data["values"][0]
canonical = items[token]
await dispatch(f"/{canonical}")
Follow the same separation for Telegram menus, tool registries, and provider/theme resolution: emitted names/values must be mapped back to the exact canonical identifier used for backend resolution, and collisions must be rejected early rather than “best-effort” resolved later.
Treat every potentially-null/nullable config subsection and external payload field as untrusted: normalize it before accessing deeper keys or calling methods.
Rules
null subsections (common in YAML):
section = cfg.get("x") or {} before section.get(...).isinstance(value, dict) (or equivalent) before nested .get().startswith):
isinstance(field, str).NameError from Optional/Any).Example
def pick_language(stt_config: dict) -> str | None:
stt_config = stt_config or {}
groq_cfg = stt_config.get("groq") or {} # handles groq: null
local_cfg = stt_config.get("local") or {}
return groq_cfg.get("language") or local_cfg.get("language")
def handle_matrix_location(payload: dict) -> None:
geo_uri = payload.get("geo_uri")
if not isinstance(geo_uri, str):
return # or safely log/drop
if geo_uri.startswith("geo:"):
...
This prevents crashes like AttributeError: 'NoneType' object has no attribute 'get' and AttributeError/TypeError from calling string methods on non-strings.
Apply a “configuration as a contract” standard: when behavior depends on environment/profile/feature flags (remote vs local, active management profile, accessibility mode, client/server timing), wire that configuration into all relevant code paths and keep its semantics consistent across layers.
Checklist
screenReaderMode) is required for a user-facing terminal, ensure equivalent terminal variants (e.g., agent/output terminals with independent constructors) receive the same option.Example patterns
// In api.ts / shared config
PROFILE_SCOPED_PREFIXES.add('/api/messaging/weixin/onboarding')
// so fetchJSON can append the active management profile
// In both terminal constructors
const termOptions = { /* ... */ screenReaderMode: true }
// Ensure client timeout constants/comments reflect the server’s real cap
export const PROFILES_REQUEST_TIMEOUT_MS = SERVER_CAP_MS // or remove misleading comments
External API boundaries must enforce the final wire contract: only supported parameters, only provider-accepted content shapes, and only schema-valid payloads.
Apply these rules in API-related code (tool dispatchers, transport builders, and request serializers):
1) Filter/allowlist request parameters at every outbound boundary
2) Validate the serialized “on-the-wire” message shape, not the internal shape
3) Keep JSON schemas consistent with runtime payload contracts
mode='replace' vs mode='patch'), the schema must not require both sets of fields.required: ["mode"] and enforce per-mode requirements via validator logic or mode-specific constraints in code.4) Centralize normalization that drives external protocol behavior
Path(...).suffix.lower()), then map to provider-valid formats.Example (parameter/body allowlist + wire-shape sanitation pattern):
# 1) Boundary allowlist for provider JSON body
WIRE_FIELDS = {"model", "input", "response_format", "temperature", "top_p"}
def build_wire_body(api_kwargs: dict) -> dict:
body = {k: v for k, v in (api_kwargs or {}).items() if k in WIRE_FIELDS}
# never include SDK-only controls (extra_headers/extra_body/timeout/stream)
return body
# 2) Final on-the-wire message sanitizer (after all transforms)
def sanitize_wire_messages(messages: list[dict]) -> list[dict]:
cleaned = []
for m in messages:
if m.get("role") == "assistant" and m.get("content") in (None, "", []) and not m.get("tool_calls"):
# only drop when it is truly empty on the wire
continue
cleaned.append(m)
# TODO: optionally repair role adjacency if you dropped a turn
return cleaned
Team standard for reviews: if a change touches request building, serialization, tool schemas, or codec/format selection, reviewers should explicitly verify (a) unknown kwargs aren’t forwarded, (b) payloads are schema-valid, and (c) the final serialized wire representation matches what the external service accepts.
Behavioral configuration must be owned by config.yaml (and documented), while environment variables must be limited to secrets or internal backward-compatibility bridges. Also ensure any filesystem default paths are profile-safe via get_hermes_home().
Apply this standard:
1) Behavioral knobs → config.yaml
config.yaml section (with defaults in DEFAULT_CONFIG) and update docs/tests.agent.*, stt.*, platforms.*.extra) over new HERMES_* behavioral env vars.2) **Env vars are allowed only for:
3) Profile-safe defaults
get_hermes_home()/...), not $HOME/.hermes or hardcoded POSIX paths.Code sketch (config-first + profile-safe default + env only as compat):
import os
from pathlib import Path
from hermes_constants import get_hermes_home
_TRUEY = {"1","true","on","yes"}
def _truthy(v: str) -> bool:
return v.strip().lower() in _TRUEY
def enabled() -> bool:
# Internal compat bridge (optional): env overrides should not be the primary surface.
env = os.environ.get("HERMES_SOME_FEATURE", "").strip().lower()
if env:
return _truthy(env)
# Primary: config.yaml (load once via existing config helpers)
from hermes_cli.config import load_config
cfg = load_config() or {}
return _truthy(str((cfg.get("agent", {}) or {}).get("some_feature", {}).get("enabled", False)))
def sink_path() -> str:
# Profile-safe default
default = get_hermes_home() / "logs" / "feature.log"
# Optional compat env override for service managers
override = os.environ.get("HERMES_SOME_FEATURE_FILE", "").strip()
return str(Path(override).expanduser()) if override else str(default)
If you’re about to introduce a new HERMES_* env var for behavior, stop and ask: “Is this truly a secret or only internal compat?” If it’s user-facing, route it through config.yaml instead.
When async work can overlap (navigation changes, optimistic updates, multiple handler invocations, or speech interruption), treat post-await mutations as conditional on the original intent. Capture (1) the state/identity you’re operating on and (2) a monotonically increasing generation/token before any await or long-running step. Only apply success/failure/rollback when the token still matches the latest value; otherwise discard the completion.
Also, ensure that “normal completion” paths (e.g., a finally that re-arms listening) are skipped when an interrupt/cancel occurred; guard them with the same interruption flag/token.
Practical pattern:
let refreshGen = 0
async function refresh() {
const gen = ++refreshGen
const requestedBoard = $kanbanActiveBoard.get() // identity snapshot
try {
const next = await getKanbanBoard(requestedBoard)
// Discard stale response
if (gen !== refreshGen) return
$kanbanBoard.set(next)
} catch (e) {
if (gen !== refreshGen) return
$kanbanBoardError.set(String(e))
}
}
async function moveOptimistic(taskId: string, targetStatus: string) {
const gen = ++moveGen
const boardAtStart = $kanbanBoard.get() // snapshot identity
$kanbanBoard.set(applyMove(boardAtStart, taskId, targetStatus))
try {
await updateKanbanTask(taskId, { status: targetStatus }, $kanbanActiveBoard.get())
if (gen !== moveGen) return
await refreshFromServer(boardAtStart)
} catch (e) {
if (gen !== moveGen) return
$kanbanBoard.set(boardAtStart) // guarded rollback
$kanbanBoardError.set(parseError(e))
}
}
Apply this rule whenever:
finally/completion handlers that would otherwise perform the wrong re-arming behavior,Result: late/stale completions stop overwriting newer intent, and both success and error paths become race-safe.
Client and UI code must explicitly follow the real API/component contract—both for what state transitions are allowed and which side effects/transport paths are actually executed.
Apply this by:
onXChange/callback can suppress the underlying action.Example pattern for transition gating:
// pseudo: fetch/derive allowed destinations for the client
const allowed = await api.getAllowedKanbanTransitions(taskId)
function onDrop(toStatus: KanbanStatus) {
if (!allowed.includes(toStatus)) return // backend will reject; avoid optimistic move
// then call backend and update UI
await api.updateKanbanTask(taskId, { status: toStatus })
await refreshBoard()
}
Outcome: fewer “optimistic” failures, fewer integration drift bugs (wrong transport), and predictable behavior when APIs/components have non-cancelable lifecycle hooks.
When behavior depends on library primitives (e.g., Radix) and real browser focus/pointer flows (including document.body portals), unit tests that reimplement internal handlers are not enough. Write tests that render the actual component tree and assert user-observable outcomes.
Apply this standard:
onOpenChange/handler) and assert the final DOM state (e.g., tooltip open/closed) and/or event delivery.:focus-visible) and keep the expectations aligned to how the product behaves.Example pattern (tooltip cancellation):
// Pseudocode: render actual TooltipPrimitive-based component
render(
<TooltipRoot /* real component */>
<TooltipTrigger asChild>
<button>Tip</button>
</TooltipTrigger>
<TooltipContent>...</TooltipContent>
</TooltipRoot>
)
// Mouse/focus path should NOT open
userEvent.click(screen.getByRole('button', { name: /tip/i }))
expect(screen.queryByText('...')).not.toBeInTheDocument()
// Keyboard focus path SHOULD open
screen.getByRole('button', { name: /tip/i }).focus()
expect(screen.getByText('...')).toBeInTheDocument()
This ensures the test verifies the real cancellation mechanism and prevents regressions involving focus and portal DOM behavior.
All untrusted inputs must be hardened at their security boundaries: (1) for network calls, validate the destination on every redirect hop (and ideally after DNS resolution), and (2) for any rendered or embedded output, sanitize/encode for the exact output context to prevent XSS and script-breaking.
Apply this standard:
redirect is enabled.<script> block, escape </script> (and other context-breaking sequences) before interpolation.</script> and unquoted onerror payloads).Example pattern for safe redirects (sketch):
async function fetchWithValidatedRedirects(initialUrl, validateHop) {
let url = initialUrl;
for (let hops = 0; hops < 5; hops++) {
validateHop(url); // block private/loopback/reserved + enforce allowlist
const res = await fetch(url, { redirect: 'manual' });
if (res.status < 300 || res.status >= 400) return res;
const loc = res.headers.get('location');
if (!loc) return res;
url = new URL(loc, url).href;
}
throw new Error('Too many redirects');
}
And for JSON-in-script embedding, ensure you escape for script context (e.g., replace </script> with <\/script> before injecting).
All profile-scoped routing must use the mechanism your IPC/bridge/router actually consumes (e.g., an outer request field or a ...profileScoped() wrapper). Do not attempt to “scope” routing by placing profile inside nested request bodies that the backend simply binds/forwards, or by passing profile only as a query param unless the bridge explicitly treats it as a routing key.
Apply the rule:
profileScoped()) at the API call site.Example pattern:
return window.hermesDesktop.api<Response>({
...profileScoped(), // routing key understood by the bridge/router
path: '/api/audio/speak',
method: 'POST',
body: { text }, // backend binding; don’t rely on body nesting for routing
});
When implementing parsing/classification logic, treat the input grammar as a contract: (1) constrain pattern matches to the intended envelope/boundaries/character sets (avoid prefix/superset regexes and overly broad Unicode ranges), (2) ensure every computed signal/metric is actually used in the final decision, and (3) add targeted regression tests for each boundary/grammar edge.
Apply:
\b, attribute-aware tag opening).Example (grammar-constrained marker stripping):
import re
def strip_asr_envelope(text: str) -> str:
# Only remove the Qwen-style start-anchored envelope, not any occurrence.
m = re.match(r"^language\s+.*?<asr_text>", text, flags=re.IGNORECASE | re.DOTALL)
if not m:
return text
# Remove the first envelope marker then keep the rest.
return text.replace(m.group(0), "", 1).strip()
Checklist for PRs in this area:
When a security-related skill or script causes any external effect (sending data to third parties, spending funds, changing auth, or modifying security config), the implementation and docs must be explicit about (a) trust boundaries, (b) user-controlled/bounded authorization, and (c) safe, targeted, verifiable changes.
Apply this standard:
sed that rewrites any enabled * yes directive).Example patterns (illustrative):
1) Don’t overclaim trust boundary
Wrong: “Redacts PII before it reaches your LLM provider.”
Right: “Hosted transformation: the skill sends input text to TrustBoost for processing, then returns sanitized output.”
2) Require bounded user approval before external spend
Before executing a swap: show {wallet, assets, amount, trigger, expiry} and require explicit user confirmation.
Reject or pause if running from a cron/unattended path without an approval token/state.
3) Use directive-scoped config edits
# Instead of rewriting any '* yes' line, edit only the intended directive.
# Then verify with sshd -T or grep before reloading.
sudoedit /etc/ssh/sshd_config
# Verify: sshd -T | grep -E 'passwordauthentication|permitrootlogin'
# Reload only after verification.
4) Firewall enable with lockout-safe rule preservation
Before ufw enable: ensure existing SSH allow rule is present (source/port as configured), then enable.
Never enable default-deny without preserving active SSH management access.
Outcome: fewer security “false assurances,” fewer accidental lockouts, and no silent/unauthorized irreversible actions.
When implementing security controls, treat them as end-to-end requirements across all navigation paths and all auth/transport interfaces. Two common failure modes are (1) hidden/aux renderer windows that still allow unintended credential/WebAuthn UI via a fallback path, and (2) security-sensitive flows that accept security context but some callers pass plain public URLs, causing bypass of the intended secure routing/transport.
Apply this standard:
Example pattern (renderer + typed IPC):
// Renderer hardening: avoid a fallback that can show credential/WebAuthn UI.
try {
window.webContents.setWindowOpenHandler(() => ({ action: 'deny' }));
window.webContents.setWebRTCIPHandlingPolicy('disable_non_proxied_udp');
// Ensure the session/policy for the title/hidden navigation suppresses
// credential/WebAuthn UI before any navigation occurs.
// (Apply/remove fallback paths so arbitrary public pages cannot slip in.)
} catch (e) {
// Fail closed or log and abort navigation.
}
// IPC/auth: always pass the fully expressive payload to prevent bypass.
// Prefer object-based inputs so transport selection can’t be derived from a public URL string.
await ipcRenderer.invoke('probeConnectionConfig', {
remoteUrl: config.remoteUrl,
// include the fields needed for effective secure routing
// (e.g., local_mtls_proxy / loopback transport metadata)
});
Result: security behavior stays consistent even during reauth/boot-failure handling and during unusual navigation/fallback scenarios.
When error handling affects control-flow invariants (dedupe keys, stale-session guards, correctness checks), make failures safe and reversible:
Example pattern (dedupe cleanup):
const dedupeKey = imageBlobDedupeKey(blob, data)
if (rememberRecentImageBlobPaste(refs, dedupeKey)) return
try {
const ok = await saveImageBuffer(...)
if (!ok) throw new Error('save failed')
} catch (e) {
// restore invariant so immediate retry can attach
forgetRecentImageBlobPaste(refs, dedupeKey)
throw e
}
Example pattern (guard integrity):
try {
const remote = await getSessionMessages(guardStoredId /* required routing */)
// decide based on remote
} catch (e) {
// safe default: block + refresh rather than submit with stale context
await refreshSessionContext()
return
}
When designing or consuming client/server APIs, keep the contract explicit and prevent duplicate logic/types from drifting.
Apply this standard:
getClient() + thin wrappers, centralize into a shared utility/hook to keep calling semantics consistent.Example patterns:
export function getSessionDisplayName(session: Session): string {
return session.name || DEFAULT_CHAT_TITLE;
}
// Prefer relying on GooseClient.initialize(...) typing
// instead of maintaining GooseInitializeRequest that can diverge.
export interface GooseExtNotifications {
unstable_sessionUpdate?: (n: GooseSessionNotification_unstable) => Promise<void>;
}
When processing security-relevant external inputs (URIs/hosts, file paths/content, auth tokens, and tool-call metadata), validate and constrain early, then ensure failure modes are non-recoverable in ways that could cause retries or duplicate effects.
Apply this pattern: 1) Validate trust boundaries
2) Constrain filesystem operations
3) Make tool execution idempotent and policy-deny non-retryable
4) Use safe auth handling
Example (pattern sketch):
// 1) Constant-time token check
fn tokens_equal_ct(expected: &str, actual: &str) -> bool {
expected.as_bytes().ct_eq(actual.as_bytes()).into()
}
// 2) Bounded read after regular-file validation
const MAX: u64 = 1024 * 1024;
fn read_bounded(mut f: std::fs::File) -> Result<Vec<u8>, anyhow::Error> {
let mut buf = Vec::new();
f.take(MAX + 1).read_to_end(&mut buf)?;
if (buf.len() as u64) > MAX {
anyhow::bail!("file exceeds limit");
}
Ok(buf)
}
// 3) Policy denial should not invite retries
// Prefer a “final tool outcome” representation over returning an MCP Err
// that could trigger a retry path.
fn deny_tool_call_final(plugin: &str, reason: &str) -> ToolCallResult {
ToolCallResult { is_error: true, final_message: format!("blocked by {plugin}: {reason}") }
}
Net: validate/normalize untrusted inputs at the boundary, strictly limit side effects (IO size/type, tool execution), use constant-time auth comparisons, and make authorization/policy denials non-retryable to prevent retry storms or duplicate execution.
When code changes affect what the app sends (RPC/HTTP payloads/options) or what the app decides based on the environment, add targeted tests that (1) assert the exact externally observable behavior and (2) make the inputs deterministic.
Practical rules:
session.create), write a regression test that triggers the path (e.g., via the hook) and asserts the exact payload contains the new field/value.timeoutMs), add a focused unit test that calls the wrapper (or mounts the relevant layer) and asserts the options passed to the underlying API client.Example (Vitest-style contract assertion):
import { describe, it, expect, vi } from 'vitest'
import { renderHook } from '@testing-library/react'
import { useSessionLifecycle } from './useSessionLifecycle'
vi.mock('../rpc', () => ({
rpc: vi.fn(),
}))
it('sends launch cwd in session.create payload', async () => {
process.env.HERMES_CWD = '/expected/launch/dir'
const { rpc } = await import('../rpc')
;(rpc as unknown as ReturnType<typeof vi.fn>).mockResolvedValue({ /* ... */ })
const { result } = renderHook(() =>
useSessionLifecycle({ /* required opts */ })
)
await result.current.newSession(/* args that lead to startNewSession */)
expect(rpc).toHaveBeenCalledWith('session.create', expect.objectContaining({
cwd: '/expected/launch/dir',
}))
})
Apply the same pattern to wrapper options (assert timeoutMs) and to environment detection (inject sysfs/DMI inputs rather than reading the host).
When an algorithm derives a decision key (dedupe) or signal (parsed config) that can suppress/merge data, make that derivation collision- and normalization-safe, and define precedence explicitly.
Dedupe keys (avoid collision-based suppression):
import { createHash } from 'node:crypto'
export function imageDedupeKey(blob: Blob, data: Uint8Array): string {
// Collision-resistant key: hash actual bytes (optionally include size)
const digest = createHash('sha256').update(data).digest('hex')
return `${blob.size}|${digest}`
}
Parsed/merged config (normalize + deterministic precedence):
function hasAnyInheritedProxy(env: Record<string, string>, family: 'http'|'https') {
const keys = [
`${family}_proxy`,
`${family.toUpperCase()}_PROXY`
]
return keys.some(k => (env[k] ?? '').length > 0)
}
Why: these patterns prevent subtle, hard-to-debug behavior like “silent suppression” from hash collisions and inconsistent merging from incomplete normalization/precedence handling.
On macOS, treat re-signing (including ad-hoc re-sign after quarantine stripping) as a security-sensitive operation: preserve the app’s entitlements for the main bundle and any helper apps. Otherwise, macOS TCC access (mic/screen audio) may break or continuously prompt because the re-signed artifacts no longer carry the expected entitlements. Also ensure every packaging/update path uses the same entitlement-preserving logic.
Practical rule:
codesign --force --deep --sign -), then re-apply the correct entitlements to both main and helper bundles.Example (bash pattern):
# Only for macOS ad-hoc path; skip when real signing is configured.
if [ "$OS" = "macos" ] && [ -z "${CSC_LINK:-}" ] && [ -z "${APPLE_SIGNING_IDENTITY:-}" ] && command -v codesign >/dev/null 2>&1; then
xattr -cr "$app" 2>/dev/null || true
main_entitlements="$desktop_dir/electron/entitlements.mac.plist"
helper_entitlements="$desktop_dir/electron/entitlements.mac.inherit.plist"
if [ -f "$main_entitlements" ] && [ -f "$helper_entitlements" ]; then
# main bundle
codesign --force --deep --sign - --entitlements "$main_entitlements" "$app" >/dev/null 2>&1 || true
# helper apps inside the bundle
while IFS= read -r -d '' helper_app; do
codesign --force --deep --sign - --entitlements "$helper_entitlements" "$helper_app" >/dev/null 2>&1 || true
done < <(find "$app" -type d -name "*.app" -print0)
fi
fi
Apply this pattern consistently across all build/update routes so security-relevant signing behavior can’t drift.
When handling errors, ensure you don’t (1) mask the original failure, (2) violate the intended timeout/retry/cleanup boundaries, or (3) make recovery decisions without explicit evidence.
Standards 1) Cleanup must never throw / must not mask the real exception
finally (e.g., worker/thread handles) or guard with getattr. class Runner:
def __init__(self):
self._tts_playback_thread = None # initialize for finally safety
def run(self):
try:
...
finally:
t = getattr(self, "_tts_playback_thread", None)
if t and t.is_alive():
t.join(timeout=5)
2) Honor deadlines everywhere (especially after streaming/pipes hit EOF)
3) Cleanup must cover the full resource scope
4) Recovery decisions must be evidence-gated
except Exception that collapses unrelated failures into the same recovery.5) Error ordering: validate ‘not found’ before operations that can raise 400/validation/unknown-task errors
6) Preserve best-effort behavior where it was intentional
Applying this standard will prevent masked exceptions, unblock deterministic cleanup/timeout behavior, and keep recovery logic correct and testable.
When multiple async operations can be in flight (polling, optimistic mutations, React effects, REST hydration + live WebSocket deltas), older responses may arrive last and overwrite newer state. Standardize a pattern that makes each async result apply only if it is still the current/owned operation.
Apply this rule:
setState, capture a “generation” (requestId) or “owner key” (e.g., selected board slug, active session id) and verify it before committing results.Example pattern (generation-aware commit):
const requestGenRef = useRef(0)
const refresh = useCallback(async () => {
const gen = ++requestGenRef.current
try {
const data = await getKanbanTasks()
// Only the latest in-flight request may update state
if (gen !== requestGenRef.current) return
setTasks(Array.isArray(data.tasks) ? data.tasks : [])
} catch (e) {
if (gen !== requestGenRef.current) return
notifyError(e)
}
}, [])
Also guard by selection/ownership:
selectedBoardSlug (or session id) used to start the request, and before set*, verify it still matches the current value.This prevents race-condition clobbering and makes state transitions deterministic under concurrency.
When code maps or normalizes external identifiers (tool names, locale tags, etc.), it must preserve the identifier’s real semantics and use canonical names.
Standards
mcp__<server>__<tool>), and only transform for display when needed.Example pattern (display-only normalization)
// Canonical external identifier (real MCP name)
type McpToolName = 'mcp__filesystem__write_file'
function displayTitle(toolName: McpToolName): string {
// Safe display-only transformation; semantics preserved
if (toolName === 'mcp__filesystem__write_file') return 'write_file'
return toolName
}
Example anti-pattern (semantic-unsafe aliasing)
// ❌ Incorrect: Belarusian/Ukrainian/Kazakh tags mapped to Russian UI
const LOCALE_ALIASES: Record<string, 'ru'> = {
be: 'ru',
uk: 'ru',
kk: 'ru'
}
// Fix by removing/correcting those mappings.
In configuration/settings UI (including timezone, system defaults, and messaging), do not introduce or hardcode user-visible text. Always source strings from the appropriate i18n catalog/keys so all locales (e.g., desktop Japanese/Chinese) get consistent wording.
Apply this rule:
t.common.messaging) instead of literals.Example pattern (web):
// Good: use localized key
const label = t.common.messaging
// Avoid:
const label = 'Messaging' // forces English
Example pattern (component string reuse):
// Good: pull “System default” and related hints from i18n
const systemDefaultText = t.config.systemDefault
When coordinating async work with shared resources, (1) tie lock/flag state transitions to the real lifecycle of the work (e.g., confirmed detached handoff or confirmed error) rather than to generic function scope, and (2) treat resource contention as transient by using bounded retry + backoff for cleanup/claims.
Apply this in two parts:
1) Lock lifecycle: clear only when it’s actually safe
finally if the process/work continues after the function returns (especially across deliberate dwell/shutdown delays). A finally can create a race window where another updater/retry can start.Example pattern (JS):
async function applyUpdates(opts = {}) {
// ... acquire lock: updateInFlight = true
try {
const { ok, handedOff, updater } = await applyUpdatesPosixInApp();
if (handedOff) {
// Keep lock through quit dwell; do NOT clear via finally.
return { ok, handedOff: true, updater };
}
// Non-handoff normal returns should release the lock.
updateInFlight = false;
return { ok, handedOff: false };
} catch (err) {
// Only on error: allow a retry by clearing lock.
updateInFlight = false;
throw err;
}
}
2) Transient contention: bounded retry with backoff
Example pattern (PowerShell):
# Attempt in-place delete with retries for transient file locks
Remove-Item -Recurse -Force 'venv' -ErrorAction SilentlyContinue
$retryDelay = 2
for ($retry = 0; $retry -lt 3; $retry++) {
if (-not (Test-Path 'venv')) { break }
Write-Info "venv still locked (attempt $($retry + 1)/3); waiting ${retryDelay}s..."
Start-Sleep -Seconds $retryDelay
$retryDelay *= 2
}
Net effect: you prevent race windows from premature lock clearing and you make cleanup operations resilient to short-lived contention—both are essential in concurrent and lifecycle-sensitive code.
In long-running UI workflows that poll (e.g., QR status, task panels, gateway actions), treat failures as transient vs permanent, and ensure your state transitions cannot loop forever.
Apply this standard:
notifyError).idle/reset phase (clearing session IDs, timers, and retry flags) rather than returning to a polling state.Example pattern:
const [pollingEnabled, setPollingEnabled] = useState(true);
const [phase, setPhase] = useState<'idle'|'waiting'|'applying'>('idle');
const [sessionId, setSessionId] = useState<string|null>(null);
async function fetchStatus() {
try {
return await api.getWeixinOnboardingStatus(sessionId!);
} catch (e: any) {
// Permanent/unsupported: stop once
if (e?.status === 404) {
setPollingEnabled(false);
setPhase('idle');
setSessionId(null);
// show unavailable UI / toast once
return null;
}
throw e; // transient -> let retry logic handle
}
}
useEffect(() => {
if (!pollingEnabled || !sessionId || phase !== 'waiting') return;
let cancelled = false;
const tick = async () => {
if (cancelled) return;
const st = await fetchStatus();
if (!st) return; // stopped/unavailable
// ...update UI, schedule next poll...
};
const id = setTimeout(() => void tick(), 1500);
return () => {
cancelled = true;
clearTimeout(id);
};
}, [pollingEnabled, phase, sessionId]);
async function apply() {
setPhase('applying');
try {
await api.applyWeixinOnboarding(sessionId!, {});
// success path...
} catch {
// Critical failure: reset to break retry loop
setPhase('idle');
setSessionId(null);
}
}
This prevents repeated error spam and eliminates auto-retry loops when the backend endpoint is unsupported or when a critical step fails.
When code crosses security boundaries (HTTP auth, subprocess execution, or policy-driven external side effects), it must follow the established secure path and validate before acting.
Use the project’s authenticated transport: Don’t bypass SDK helpers with ad-hoc fetch/manual token headers. Forward extra headers (e.g., locale) via the helper’s options so cookie-based/OAuth flows remain intact.
// Prefer the SDK helper that preserves cookie/OAuth behavior
return SDK.fetchJSON(url, {
method: 'GET',
headers: {
...(locale && locale !== 'en' ? { 'Accept-Language': locale } : {}),
// do not manually inject window tokens if the SDK already handles auth
},
});
Prevent command injection: Never build a shell command string from untrusted inputs. Use argument-vector subprocess APIs.
// Unsafe (shell string composition): avoid
// execSync(`ffmpeg -i "${file}" ...`)
// Safe: argument array
execFileSync('ffmpeg', ['-i', filePath, /* ... */], { stdio: 'inherit' });
Gate privileged side effects: Validate authorization/policy and required identifiers before queueing or emitting actions. Only collect/execute the side effect after admission checks pass.
const queued = [];
for (const msg of messages) {
if (!msg.key || msg.key.fromMe) continue;
const chatId = msg.key.remoteJid;
if (!chatId || chatId.endsWith('@broadcast') || chatId.endsWith('@g.us')) continue;
// enqueue only after policy gates/allowlists have been applied
if (passesAdmissionChecks(msg)) queued.push(msg.key);
}
Apply these rules consistently to reduce auth regressions (401/OAuth gating), injection risk, and inadvertent disclosure/side effects from policy mistakes.
When integrating LLM providers, don’t assume the provider’s model spec equals what the specific API endpoint will actually accept. Enforce two checks in your model configuration: (1) set context_limit to a safe upper bound that matches the endpoint’s effective cap, and (2) restrict model selection to a curated allowlist of chat-capable models instead of auto-loading the full /v1/models catalog (which can include unsupported modalities).
Practical application:
context_limit accordingly or keep a conservative cap until confirmed otherwise.dynamic_models to false and maintain an explicit list of supported chat models.Example (pattern):
{
"api_key_env": "PROVIDER_API_KEY",
"base_url": "https://api.provider.com/v1/chat/completions",
"dynamic_models": false,
"models": [
{ "name": "Chat-Model-A", "context_limit": 200000 },
{ "name": "Chat-Model-B", "context_limit": 64000 }
]
}
In React components and hooks, changes to focus/interaction state or derived UI state must preserve correct behavior for all users and reflect the actual semantic state transitions.
Apply this standard: 1) Interactive controls: ARIA + roving focus requires keyboard support
tabIndex (only the active tab is focusable), you must also implement expected keyboard navigation (typically ArrowLeft/ArrowRight/Home/End) to move focus/selection among tabs.Example (tablist pattern):
function onTabKeyDown(e: React.KeyboardEvent, tabs: Tab[], currentId: string) {
const idx = tabs.findIndex(t => t.id === currentId)
const move = (nextIdx: number) => {
const next = tabs[(nextIdx + tabs.length) % tabs.length]
selectTab(next.id) // set active + update tabIndex
focusTabButton(next.id) // optional: focus the newly selected tab button
}
switch (e.key) {
case 'ArrowLeft': e.preventDefault(); move(idx - 1); break
case 'ArrowRight': e.preventDefault(); move(idx + 1); break
case 'Home': e.preventDefault(); move(0); break
case 'End': e.preventDefault(); move(tabs.length - 1); break
}
}
2) Hooks/effects: rerun on the semantic inputs, not just “session changes”
useEffect dependency lists include the values that should trigger the behavior (e.g., language/locale).Example (separate locale-independent selection from locale-dependent text):
type PlaceholderSelection = { kind: 'new'|'followUp'; index: number }
function getPlaceholderText(sel: PlaceholderSelection, locale: string) {
const templates = sel.kind === 'new' ? newTemplatesByLocale[locale] : followUpTemplatesByLocale[locale]
return templates[sel.index]
}
// Keep sel stable; derive text from locale
const [sel, setSel] = useState<PlaceholderSelection>(() => ({ kind, index }))
const text = getPlaceholderText(sel, locale)
Net effect: keyboard-only users can operate interactive tab UI reliably, and hooks update derived text/state correctly when language or other semantic inputs change—without unintended rerolls or history resets.
When you describe an algorithm (retrieval pipeline, scoring, ranking, etc.), ensure the implementation includes the complete promised workflow and produces deterministic outputs.
Apply this checklist:
Example pattern (scoring determinism):
from dataclasses import dataclass
@dataclass(frozen=True)
class Checks:
ssh_root_login: bool
open_ports: tuple[int, ...] # ensure stable ordering
updates_installed: bool
def score(checks: Checks) -> int:
# Deterministic, explicit per-check points
points = 0
points += 25 if not checks.ssh_root_login else 0
points += 25 if len(checks.open_ports) == 0 else max(0, 25 - 5*len(checks.open_ports))
points += 20 if checks.updates_installed else 0
# ... add the remaining dimensions with explicit point math
return max(0, min(100, points))
def collect_read_only() -> Checks:
# Only read system state; normalize ordering; no mutations
open_ports = tuple(sorted(_read_open_ports()))
return Checks(
ssh_root_login=_read_ssh_root_login(),
open_ports=open_ports,
updates_installed=_read_updates_installed(),
)
For retrieval workflows, use the same idea: document and implement every required step (index build, pass 1 retrieval, pass 2 expansion/retrieval, result merge, and the call site), or explicitly limit the documentation to the implemented subset.
When using OpenAI-compatible providers/proxies, treat authentication and endpoint routing as separate concerns:
OPENAI_API_KEY). If the key is missing/unloaded, requests may be sent with no auth and you’ll typically see 401 (e.g., No api key passed in).OPENAI_HOST as the proxy root without a trailing path, and OPENAI_BASE_PATH as the served route such as v1/chat/completions). If the path is wrong, you’ll typically see 404 for the expected operation/route.Example (proxy via OpenAI-compatible settings):
# Proxy root only (no trailing path)
export OPENAI_HOST="https://your-proxy.example.com"
# Path the proxy serves (ensure it matches, e.g., v1/chat/completions)
export OPENAI_BASE_PATH="/v1/chat/completions"
# Auth token used by the client
export OPENAI_API_KEY="$YOUR_KEY"
Practical troubleshooting:
OPENAI_API_KEY is set and loaded.chat/completions → fix OPENAI_BASE_PATH (and verify it matches what the proxy actually exposes).Write Rust code so its intent is clear at a glance and responsibilities are placed correctly.
Apply this checklist:
if edit && fork / else if shapes into a single flow that reuses the right helper methods.Example pattern for readability (intermediate variables + simplified conditions):
let requested_budget = thinking_budget_tokens(model_config);
let max_thinking_budget = max_tokens.saturating_sub(MIN_ANSWER_TOKENS);
let budget_tokens = requested_budget.min(max_thinking_budget);
if budget_tokens >= MIN_THINKING_BUDGET_TOKENS {
// build the thinking config using budget_tokens
}
When integrating LLM providers/models, derive capability flags and limits from canonical model metadata (catalog) and apply deterministic compatibility rules with explicit fallbacks—avoid brittle name-based heuristics and keep user overrides authoritative.
Apply these practices:
context_limit/max_tokens from a catalog, override only when the user/config limit is unset or the documented sentinel; cap max_tokens to the effective context (user override wins).output_tokens where needed) so downstream logic and cost accounting remain consistent.Example pattern (resolve limits with canonical fallback while honoring user overrides):
pub fn with_catalog_provider_fallback(mut self, catalog_provider_id: &str) -> Self {
let canonical = maybe_get_canonical_model(catalog_provider_id, &self.model_name);
if let Some(c) = canonical {
// only override when user didn’t set a real limit
if self.context_limit.is_none() || self.context_limit == Some(0) {
self.context_limit = Some(c.limit.context);
}
// cap to effective context (not the raw catalog context)
if self.max_tokens.is_none() {
let effective_ctx = self.context_limit.unwrap_or(c.limit.context);
self.max_tokens = c.limit.output
.filter(|&out| out < effective_ctx)
.map(|out| out as i32);
}
}
self
}
When publishing extension/server install options (especially deep-links or Install buttons), default to a secure-by-default path: require explicit/manual installation for binary-first or otherwise security-sensitive extensions. Only enable an automated install/deeplink if the target is explicitly allowlisted.
Apply it like this:
show_install_link to false).deeplink.ts with a narrow entry for the exact server/extension (no broad or dynamic matching).Example (pattern):
{
"id": "nika",
"name": "Nika",
"description": "...",
"command": "nika mcp",
"show_install_link": false
}
Then document manual install, e.g.:
goose session --with-extension "nika mcp"Security-sensitive state (e.g., creating/persisting a profile that assumes a working remote connection) must not be created when required authentication material is missing or invalid. If downstream token-auth/config saving will reject empty/placeholder tokens, block the flow up front or use a staged/OAuth flow so the local profile is only finalized after auth/config persistence succeeds. If you can’t guarantee that, roll back local changes when remote auth/config saving fails.
Example pattern (block or stage before creating):
async function createRemoteProfile(params: {
backendMode: 'remote' | 'local';
token?: string;
/* ... */
}) {
if (params.backendMode === 'remote') {
const token = params.token?.trim();
if (!token) {
throw new Error('Token required for remote connection');
// OR initiate OAuth/staged setup here and return.
}
// Only after token is present, persist remote config.
await window.hermesDesktop?.saveConnectionConfig?.({
mode: 'remote',
token,
});
}
// Create/finalize local profile only after remote config succeeds.
await createProfileAndPersist();
}
Apply a production/packaged hardening rule: in release builds, only use trusted origins and trusted code/resources. Treat environment variables, URLs, and “implicit” host paths as untrusted inputs, and explicitly gate/validate them so they cannot redirect critical behavior.
How to apply:
file:///null-origin behaviors in packaged UI; ensure packaged assets are served from a deterministic scheme/origin via a controlled protocol handler.isPackaged (or equivalent release flag) is true.Example pattern (combined):
// 1) Stable, non-file origin for packaged renderer
let packagedProtocolRegistered = false;
function registerPackagedRendererProtocol() {
if (MAIN_WINDOW_VITE_DEV_SERVER_URL || packagedProtocolRegistered) return;
session.fromPartition(GOOSE_SESSION_PARTITION).protocol.handle(
PACKAGED_RENDERER_PROTOCOL,
async (request) => {
// Resolve to bundled resources only
const resolved = resolvePackagedRendererPath(
request.url,
getPackagedRendererRoot()
);
if (!resolved) return new Response('Not found', { status: 404 });
const data = await fs.readFile(resolved);
return new Response(new Uint8Array(data), {
headers: { 'Content-Type': rendererContentType(resolved) },
});
}
);
packagedProtocolRegistered = true;
}
function getAppUrl(): URL {
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) return new URL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
registerPackagedRendererProtocol();
return packagedRendererUrl();
}
// 2) Reject env override in packaged builds
export function findGooseBinaryPath({ isPackaged, resourcesPath }: {
isPackaged?: boolean;
resourcesPath?: string;
} = {}): string {
const envPath = process.env.GOOSE_BINARY;
if (envPath) {
if (isPackaged) {
throw new Error('GOOSE_BINARY override is not allowed in packaged builds');
}
// dev/test: resolve & validate
const resolved = path.resolve(envPath);
if (existingFile(resolved)) return resolved;
throw new Error('Invalid GOOSE_BINARY path');
}
// packaged: only use bundled resources
const bundled = resourcesPath ? path.join(resourcesPath, 'bin', 'goose') : '';
if (existingFile(bundled)) return bundled;
throw new Error('Bundled goose binary not found');
}
Outcome: release behavior becomes deterministic and resistant to attacker-controlled origin or configuration inputs, reducing security risk while keeping dev/test ergonomics.
Coding standard: Centralize configuration/credential semantics and never “re-derive” them in multiple places. Read from the real sources (env/config and provider-specific runtime credential caches), preserve provider identity during legacy interop, and let canonical normalizers own final resolution.
Apply this as follows:
ProviderMetadata config keys.normalize_* logic to skip important normalization steps; pass raw model inputs to the canonical normalizer.Example pattern (shared usable gate):
// Single source of truth used by both server + CLI
pub fn provider_is_usable(meta: &ProviderMetadata, provider_type: ProviderType) -> bool {
// handle local override
if meta.name == "local" { return true; }
// OAuth/token-cache-backed providers must consult inventory/configured signals
// (not just meta.config_keys)
if meta.config_keys.iter().any(|k| k.oauth_flow) {
return provider_inventory_configured(meta.name.as_str());
}
// For non-OAuth providers: require explicit config/secret presence (not only defaults)
required_keys_all_present_and_secrets_real(meta)
}
Apply security controls at the controlling layer and before triggering any side effects.
sandbox on ancestor iframes as the effective policy for descendants. Ensure the default sandbox includes any permissions required by the hosted app (otherwise functionality may break or be silently over-restricted).Example pattern:
// (1) Correct effective sandbox policy at the controlling layer
iframe.setAttribute(
'sandbox',
sandbox.permissions || 'allow-scripts allow-same-origin allow-forms'
);
// (2) Early allowlist enforcement before backend side effects
const uri = new URL(link).searchParams.get('uri');
if (!uri) throw new Error('mcp deep link is missing the uri parameter');
// allowlist check MUST happen BEFORE discoverExtension
if (!isAllowedMcpUri(uri)) {
throw new Error('Blocked MCP URI by allowlist');
}
const { data, error } = await discoverExtension({ body: { uri } });
// (defense in depth) optionally re-check resolved endpoint/host here
Use this as a review checklist for any code that: 1) constructs sandboxed browsing contexts, or 2) accepts URIs/deep links and performs discovery/network calls.
For CI/CD that builds/publishes documentation (or any release-time artifacts), ensure two things:
1) Correct trigger coverage: docs-only changes must run the docs build via an explicit workflow path (don’t assume upstream jobs will run). If you use paths-ignore to skip heavy pipelines on doc changes, add a separate workflow (or separate trigger) that fires on documentation/** so docs always get published.
2) Reproducible source fetching: when the workflow or docs install script clones external repos, pin to an immutable commit SHA (not a moving tag) so outputs can’t change unexpectedly.
Example (workflow trigger separation):
# docs-bundle.yml
on:
workflow_call:
inputs:
force_build: { type: boolean }
push:
branches: [main, "release/*"]
paths:
- "documentation/**"
workflow_dispatch:
Example (immutable pin in an installer script):
HERDR_SETUP=$(mktemp -d) && \
git clone https://github.com/modib/agent-toolkit.git "$HERDR_SETUP" && \
cd "$HERDR_SETUP" && \
git checkout bfe921c7608861c58ea37aac981b32eb3032915e
When async flows drive UI state (events, config reads, resume/load), never assume timing/order will be favorable. Make initialization idempotent and conditionally applied so missed/early events or late async completions can’t leave the UI stuck or clobber user intent.
Apply these rules: 1) Provide a “catch-up” path for state that may already be loaded.
2) Guard against out-of-order async updates.
Example pattern (session event + immediate catch-up):
const loadForSession = (id: string) => {
// load extensions for id (idempotent)
};
const onLoaded = (event: Event) => {
const targetSessionId = (event as CustomEvent<{ sessionId?: string }>).detail?.sessionId;
if (targetSessionId !== sessionId) return;
loadForSession(targetSessionId!);
};
window.addEventListener(AppEvents.SESSION_EXTENSIONS_LOADED, onLoaded);
// catch-up: don’t rely solely on whether the event already fired
loadForSession(sessionId);
Example pattern (async config read without clobbering user choice):
let userTouched = false;
// set userTouched = true in your dropdown onChange
const effortFromConfig = await readConfig('SOME_EFFORT_KEY');
if (effortFromConfig && !userTouched) {
setEffort(effortFromConfig);
}
Keep “ordering hazards” (e.g., user actions during resume vs backend load) scoped or explicitly disabled unless you can key off a reliable in-progress signal; otherwise treat them as separate follow-ups to avoid mixing multiple concurrency risks in one change.
Add comments that explain why the code behaves as it does—especially for platform-specific/terminal/UI quirks—and explicitly document any partial implementation.
Apply this standard:
Example pattern:
// On Windows Terminal (including WSL), Ctrl+V is intercepted by the terminal.
const pasteKey = process.platform === "win32" ? "alt+v" : "ctrl+v";
// Wrap link text in OSC 8 hyperlink sequences for terminal click support.
const osc8Open = `\x1b]8;;${url}\x07`;
const osc8Close = `\x1b]8;;\x07`;
result += osc8Open + linkText + osc8Close;
// Limitation: only SGR is tracked for styling state.
// OSC 8 state isn’t tracked yet, so only the first segment is clickable.
// Follow-up: extend the ANSI/terminal wrapping logic to include OSC 8 boundaries.
When your tooling downloads/execut es external installers or scripts, treat both the source and the workspace as security-sensitive:
mktemp -d) rather than a predictable hardcoded path, so pre-existing/stale files can’t affect the install.Example (bash):
set -euo pipefail
# 1) Immutable source pin
REPO_URL="https://github.com/modib/agent-toolkit.git"
PIN="v1.0.0" # or better: a commit SHA
# 2) Unique workspace
WORKDIR="$(mktemp -d)"
trap 'rm -rf "$WORKDIR"' EXIT
git clone "$REPO_URL" "$WORKDIR/herdr-setup"
cd "$WORKDIR/herdr-setup"
git checkout "$PIN"
# Execute installer from the pinned content
bash "goose/plugins/herdr/install.sh"
Apply this standard to any build/install/automation steps that clone repos, download scripts, or run them from a working directory.
When designing/adjusting API surfaces, ensure (1) consumers can clearly understand what they’re setting and what defaults apply, (2) implementation-only details don’t leak into public types, and (3) variant-specific behavior is routed through dedicated abstractions/resolvers rather than embedded special-cases.
Guidelines:
Example (options + explicit defaults + no internal leakage):
export interface AgentSessionOptions {
source?: "interactive" | "rpc" | "extension"; // public, documented
}
export function createAgentSession(opts: AgentSessionOptions = {}) {
const source = opts.source ?? "interactive";
// ...
}
// Avoid embedding provider-specific branching in unrelated call paths:
function resolveBaseUrl(model: { provider: string; baseUrl: string }) {
if (model.provider === "cloudflare") return resolveCloudflareBaseUrl(model);
return model.baseUrl;
}
Apply this checklist whenever you modify exported types, request/response shapes, client interfaces, or any public function signatures that other teams/code depends on.
Integration/E2E tests should be structured and isolated: use consistent fixture setup/teardown to avoid flakiness and leftover files, and organize higher-level tests using reusable helpers and known-good inputs/models.
Apply this standard:
Example (fixture + cleanup):
import { afterEach, describe, it, expect } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
describe("some integration", () => {
let tempDir: string;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), "pi-test-"));
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it("does the thing", () => {
// use tempDir safely
expect(tempDir).toBeTruthy();
});
});
Example (provider-organized E2E/unit structure sketch):
describe("openrouter provider", () => {
const knownGoodModel = "<provider-specific model>";
// shared helper used by multiple subtests
const runProviderTest = (input: unknown) => {/* call provider with knownGoodModel */};
it("does X", async () => {
const result = await runProviderTest({/* ... */});
// assert
});
});
Keep the repository’s module structure and implementations cohesive and non-redundant.
Apply these rules:
core/skills/ with only an index.ts/types.ts that add no navigation or separation value; keep the public surface where it’s simplest.source), extract a single shared implementation and parameterize the difference.Example (dedupe loaders by parameterizing the difference):
function loadSkillsFromDir(dir: string, source: SkillSource): Skill[] {
// shared parsing + file scanning logic here
}
// instead of two nearly identical functions
const piSkills = loadSkillsFromDir(piDir, "pi");
const claudeSkills = loadSkillsFromDir(claudeDir, "claude");
When changing config schemas, treat migrations as part of the API contract: migrations must be safe under partial/legacy states and must not cause read/write skew that overwrites migrated data.
Practical standard:
1) Backfill before cleanup: if legacy keys are being removed while the new structured block exists, first reconstruct any missing new keys needed to preserve user intent (e.g., active_provider), then delete legacy keys.
2) Prevent clobbering across read vs write: ensure the code path that reads values used to construct a write payload sees the same logical (post-migration) state, or explicitly preserve fields that the migration may have created.
3) Use runtime guards for legacy placeholders: if old entries used sentinel values, detect them during lookup/migration and correct behavior without requiring disk rewrites.
4) Split migrations by side effects, but keep behavior consistent: if load() intentionally does not persist provider migrations, then any logic that constructs persisted updates must account for that (e.g., preserve active provider fields after migration).
Example pattern for (2): preserve the migrated model only when updating the active provider; otherwise write a new empty/default model.
let model = if goose::config::get_active_provider(config)
.as_deref()
== Some(provider_name.as_str())
{
config.get_goose_model().unwrap_or_default() // preserved for active provider
} else {
String::new() // new provider
};
goose::config::set_provider_entry(
config,
&provider_name,
&goose::config::ProviderEntry {
enabled: true,
model,
configured: true,
},
)?;
Apply this style whenever a migration changes where authoritative fields live (flat keys → structured blocks, sentinel fixes, etc.).
When code uses externally influenced data (URLs, hostnames, user-provided strings, identifiers) across trust boundaries, treat it as hostile and apply layered defenses:
host.docker.internal should be blocked or allowed based on your threat model).noqa/suppression for insecure primitives (e.g., MD5) unless there’s a clearly justified reason and the rationale is documented.Example (network cap + safe client pattern):
import httpx
timeout = 5.0
max_size = 50 * 1024 * 1024 # 50MB
response = _get_ssrf_safe_client().get(image_source, timeout=timeout)
response.raise_for_status()
content_length = response.headers.get("content-length")
if content_length and int(content_length) > max_size:
return None
buf = bytearray()
for chunk in response.iter_bytes():
buf.extend(chunk)
if len(buf) > max_size:
return None
If you apply this standard consistently, you reduce SSRF and resource-exhaustion risk while also preventing unsafe rendering/templating behavior and avoiding “security bypass by suppression.”
For any security-sensitive policy/matching logic (authZ/exec policies, allow/deny rules, pattern matching), always canonicalize the relevant inputs before matching, and ensure edge cases like absolute-path .. are handled safely to prevent bypass.
Apply:
./..) before applying glob/prefix/pattern checks... consistently (e.g., /../foo should normalize to /foo, not escape the root).Example pattern (self-contained):
fn normalize_path(value: &str) -> String {
let raw = value.trim().replace('\\', "/");
let absolute = raw.starts_with('/');
let mut segs: Vec<&str> = Vec::new();
for s in raw.split('/') {
match s {
"" | "." => {}
".." => {
if !absolute {
// For relative paths, preserve leading ..
if segs.is_empty() || *segs.last().unwrap() == ".." {
segs.push(s);
} else {
segs.pop();
}
} else {
// For absolute paths, clamp: `/../foo` -> `/foo`
if !segs.is_empty() && *segs.last().unwrap() != ".." {
segs.pop();
}
}
}
_ => segs.push(s),
}
}
let mut out = String::new();
if absolute { out.push('/'); }
out.push_str(&segs.join("/"));
out
}
// Security regression test idea:
// assert!(!matches_policy("/src/**", normalize_path("/src/../secret.txt")));
This prevents attackers from exploiting normalization gaps to make /src/../secret.txt incorrectly match a /src/**-style rule.
For security-sensitive flows (WS/API, authenticated cloning, token/API-key auth), don’t rely on generic or heuristic validation.
Apply these rules: 1) Validate with explicit allow/deny semantics
2) Decide authorization/authZ at the destination handler
3) Add regression tests for both positive and negative cases
Minimal pattern to follow:
Example (illustrative):
@socketio_server.event
async def connect(sid, environ, _auth):
with webapp.request_context(environ):
origin_ok, reason = validate_ws_origin(environ)
if not origin_ok:
return False
return True # authorization/CSRF requirements enforced by the target handler
@pytest.mark.parametrize(
"url,should_accept",
[
("https://host/org/repo.git", True),
("git@host:org/repo.git", True),
("ssh://alice@host/org/repo.git", True),
("ssh://host/org/repo.git", False),
("javascript://host/org/repo.git", False),
],
)
def test_url_validation(url, should_accept):
assert is_valid_clone_url(url) is should_accept
Apply a consistent null/empty handling pattern for configuration and user-provided values:
"") as invalid rather than silently falling back. Prefer behavior that surfaces a clear configuration error.None from prompt/selection flows). Fail gracefully and consistently.strip()), validate required fields, and handle the empty/None case explicitly.Example pattern:
import os
# 1) Empty env values should not silently fall back
base_url = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434/v1")
# If base_url is "", downstream will raise a clear configuration error.
# 2) Guard nullable/custom inputs
value = prompt_fn() # may return None or ""
if value is None:
# graceful exit / clear error
raise ValueError("Missing model name")
model = value.strip()
if not model:
raise ValueError("Please enter a model name.")
# 3) In tests, assert error behavior for None/empty cases
This prevents “quiet localhost” (or other misleading defaults) and ensures null/empty misconfigurations are visible, handled safely, and protected by test coverage.
Ensure every required value is explicitly initialized/propagated across both configuration variants and process boundaries. Do not rely on “it will be set implicitly” behavior—new fields or external inputs can end up effectively undefined/empty.
Example (theme variants):
pub struct UiTheme {
pub header_bg: Color,
pub footer_bg: Color,
// ...
}
impl UiTheme {
pub fn dark() -> Self {
Self {
header_bg: Color::from_rgb(0,0,0),
footer_bg: Color::from_rgb(20,20,20), // set everywhere
}
}
pub fn light() -> Self {
Self {
header_bg: Color::from_rgb(255,255,255),
footer_bg: Color::from_rgb(235,235,235), // set everywhere
}
}
}
Example (external input):
// Prefer passing the value in the exact parameter/variable form the command expects,
// rather than assuming redirected stdin will populate it.
let mut child = Command::new("powershell.exe")
.args(["-NoProfile", "-Command", "Set-Clipboard -Value $input"]);
// ...then wire up $input per the intended mechanism and check the exit status.
Treat Vercel deployment as a configuration contract: declare dependency/version/runtime settings explicitly and align your code layout with Vercel’s discovery (or override it explicitly).
Apply this standard:
1) Pick the correct dependency manifest/lock strategy
pyproject.toml as the primary manifest.uv.lock / pylock.toml for pyproject.toml projects). Don’t mix Pipfile lockfiles as “the” lock for pyproject.toml projects.2) Declare supported Python versions
.python-version (e.g., 3.13).project.requires-python with a bounded range (e.g., >=3.12,<3.15).3) Ensure entrypoint discovery always works
app.py, main.py, asgi.py in the root or src/, app/, api/).app, application, or handler.[tool.vercel].entrypoint.4) Match framework “shape” to dependencies
uvicorn); Flask (WSGI) should not rely on ASGI server wiring.5) Don’t make discovery depend on missing local env/config
Example pyproject.toml wiring:
[project]
requires-python = ">=3.12,<3.15"
[tool.vercel]
entrypoint = "api/main.py"
If Vercel reports entrypoint/callable not found, fix it by updating (a) the entrypoint path override, (b) conventional filename/path placement, and (c) top-level callable exports—then ensure any required env/settings are configured in Vercel.
Use consistent, typed exceptions at the point of failure, with structured context, and never rely on unchecked/bypassed paths that convert errors into later crashes.
Apply:
OpenAIError) for all credential/installation/mode-resolution issues; wrap underlying exceptions via raise ... from exc.ContentFormatError) that includes actionable context (such as raw_content).raise NewError(...) from exc and don’t manually set __cause__.Example (parsing boundary):
try:
model_parse_json(MyModel, content) # or TypeAdapter(...).validate_json
except (pydantic.ValidationError, json.JSONDecodeError) as exc:
raise ContentFormatError(raw_content=content, error=exc) from exc
Example (polling boundary):
start = time.time()
while not until(response):
if time.time() - start > TIMEOUT_SECS:
raise OpenAIError("Polling timed out")
response = self.request(...)[0]
This reduces mystery failures (like KeyError) and makes errors actionable for users and tests.
Security-sensitive code must ensure (1) the correct auth path is used without accidental overrides, (2) sensitive auth material is never leaked in logs, and (3) auth-mode “sentinels” and provider handles can’t be accidentally triggered or misused.
Apply these rules:
Authorization if a user may have provided one. If you must set it, gate it behind an explicit “header missing/expected mode” check.api-key and authorization) and ensure all response/request logging uses it; cover it with unit tests.Example (redact sensitive headers):
SENSITIVE_HEADERS = {"api-key", "authorization"}
def redact_sensitive_headers(headers: dict[str, str]) -> dict[str, str]:
return {k: ("<redacted>" if k.lower() in SENSITIVE_HEADERS else v) for k, v in headers.items()}
Example (auth provider discipline):
_refresh_api_key() (or refresh a callable provider) when you’re about to use API-key auth (i.e., when AD token auth isn’t active / you’re falling back). Add tests that assert the provider is not called when AD auth is used.Write tests that are pytest-native, high-signal, and behavior-focused.
Apply these rules:
auth_headers is accessed), not just that a helper method mutates a field.unittest.TestCase version if a pytest equivalent already exists.@pytest.mark.asyncio if your environment/setup requires it.Example (high-signal header behavior):
def test_auth_headers_set_before_request() -> None:
client = OpenAI(base_url=base_url, api_key=lambda: "test_bearer_token")
# Access/trigger the behavior you actually rely on at request time
client.auth_headers # should force/ensure correct Authorization value
assert client.auth_headers["Authorization"] == "Bearer test_bearer_token"
Example (parametrize endpoints):
@pytest.mark.parametrize("path", ["/images/generations", "/chat/completions"])
def test_model_stripped_from_body(client: Client, path: str) -> None:
req = client._build_request(
FinalRequestOptions.construct(method="post", url=path, json_data={"model": "gpt-image-1-5", "prompt": "sunset"})
)
assert "model" not in req.json
Example (inline snapshot idea):
def test_schema_snapshot() -> None:
schema = to_strict_json_schema(MyModel)
assert schema == {"type": "object", "additionalProperties": False, "properties": {...}, "required": [...]}
# or use an inline snapshot if your codebase supports it
Example (lazy import regression assertion):
import importlib
import openai
m1 = openai.types
m2 = importlib.reload(openai.types)
assert m1 is m2
Technical documentation—especially troubleshooting guides—must let contributors go from symptom to reproducible diagnosis with minimal guesswork.
Apply these rules:
reports/<ticker>_<timestamp>/).Example structure to follow:
reports/<ticker>_<timestamp>/Result: docs become operational (tool/paths-driven), deterministic (pattern → first inspection), and clear about constraints (compatibility vs local environment).
Maintain configuration in a single, consistent way across the codebase:
None, resolve them via config defaults (and document why). Prefer provider-specific keys so changing one provider doesn’t silently alter another.Example pattern (provider-specific defaults + None fallback):
def get_global_news(curr_date, look_back_days: int | None = 7, limit: int | None = 50) -> dict:
# Resolve None via provider-specific config keys
if look_back_days is None:
look_back_days = DEFAULT_CONFIG.get("global_news_look_back_days", 7)
if limit is None:
# Keep Alpha Vantage historical default separate from other providers
limit = DEFAULT_CONFIG.get("av_global_news_limit", 50)
...
Follow-up actions when issues are found:
When changing business logic that affects output shape/order or resolution rules, add regression tests that assert observable outcomes for edge cases, and keep the suite maintainable by parameterizing repeated mock/assert patterns.
Apply it like this:
Example pattern (parameterized warning tests):
import warnings
import unittest
from unittest.mock import patch
class UnknownModelWarningTests(unittest.TestCase):
def assert_one_user_warning(self, warning_records, provider, model):
self.assertEqual(len(warning_records), 1)
self.assertIs(warning_records[0].category, UserWarning)
self.assertIn(f"Unknown {provider} model '{model}'.", str(warning_records[0].message))
def test_unknown_model_warns(self):
cases = [
("OpenAI", "tradingagents.llm_clients.openai_client.UnifiedChatOpenAI", "fake-openai-model"),
("Anthropic","tradingagents.llm_clients.anthropic_client.ChatAnthropic","fake-claude-model"),
("Google", "tradingagents.llm_clients.google_client.NormalizedChatGoogleGenerativeAI", "fake-gemini-model"),
]
for provider, patch_path, model in cases:
with self.subTest(provider=provider, model=model):
with patch(patch_path, side_effect=lambda **kwargs: kwargs):
with warnings.catch_warnings(record=True) as warnings_list:
warnings.simplefilter("always")
# call the provider client get_llm() here
llm = ...
self.assertEqual(llm["model"], model)
self.assert_one_user_warning(warnings_list, provider, model)
Also, for limit/order-sensitive behavior, ensure your test locks in the final observable output (e.g., count of headers) after all transformations, not just intermediate steps.
When an operation is deterministic and expensive (often due to external IO like yfinance), avoid doing the same work twice. Use bounded memoization for repeated lookups and explicitly short-circuit cases where two inputs resolve to the same underlying entity. Also ensure caches don’t leak between tests.
Practical rules:
maxsize.autouse fixture).Example pattern:
from functools import lru_cache
import yfinance as yf
@lru_cache(maxsize=128)
def company_name(ticker: str) -> str:
return yf.Ticker(ticker).info.get("longName") or ""
def fetch_returns(ticker: str, benchmark: str, trade_date, end_str):
stock = yf.Ticker(ticker).history(start=trade_date, end=end_str)
# Avoid redundant external call when both refer to the same entity
if benchmark == ticker:
bench = stock
else:
bench = yf.Ticker(benchmark).history(start=trade_date, end=end_str)
# ...compute metrics using stock and bench...
return stock, bench
When handling failures, prefer predictable, safe behavior over broad or crash-prone exception handling—especially around filesystem, JSON parsing, network calls, and user/CLI boundaries.
Practical rules: 1) Handle “expected missing” safely (filesystem)
2) Degrade gracefully on corrupted/unreadable data (JSON/parse)
3) Narrow exception types for network/API
4) Use consistent, cross-platform encodings for text I/O
Example pattern:
from pathlib import Path
import json
import requests
def clear_checkpoint_files(data_dir: Path) -> int:
cp_dir = data_dir / "checkpoints"
for db in cp_dir.glob("*.db"):
for p in (db, db.with_name(f"{db.name}-wal"), db.with_name(f"{db.name}-shm")):
if p.exists():
p.unlink()
return 0
def load_persisted(path: Path) -> dict:
try:
if not path.exists():
return {"situations": [], "recommendations": []}
return json.loads(path.read_text(encoding="utf-8"))
except (json.JSONDecodeError, OSError):
# Corrupt/unreadable → safe default
return {"situations": [], "recommendations": []}
def save_persisted(path: Path, payload: dict) -> None:
tmp = path.with_suffix(".tmp")
tmp.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
tmp.replace(path)
def fetch_with_best_effort(url: str) -> dict | None:
try:
resp = requests.get(url, timeout=30)
resp.raise_for_status()
return resp.json()
except requests.exceptions.RequestException:
return None
# Cross-platform log write
# with open(log_file, "a", encoding="utf-8") as f:
# f.write(...)
Result: the app won’t crash on common real-world failure scenarios, errors are easier to reason about (because exceptions are specific), and behavior remains consistent across platforms and environments.
When configuring Docker bind mounts (or any persistence paths), set the container mount target to exactly where the application writes at runtime—especially when code uses relative paths like Path.cwd() / "...". Don’t pick mount targets by convention; derive them from the actual path resolution logic.
How to apply:
save_report_to_disk()), and note the base path (often Path.cwd()).WORKDIR) so Path.cwd() resolves to a specific absolute path in the container.Example:
# writes to a path relative to the container working directory
out_path = Path.cwd() / "reports"
out_path.mkdir(parents=True, exist_ok=True)
# bind the host reports dir to the container cwd-resolved reports dir
services:
app:
working_dir: /home/appuser/app
volumes:
- ./reports:/home/appuser/app/reports
This ensures user-facing generated artifacts persist to the intended host location, rather than accidentally redirecting only unrelated logs or internal files.
When building provider requests or consuming provider responses, enforce that all intermediate representations match the provider’s expected wire format at the boundary—including IDs, message/content blocks, and versioned behavior.
Practical rules: 1) Translate/standardize provider-specific formats at payload-construction time (don’t assume downstream components share the same schema).
stream=False before payload construction, and strip internal-only kwargs so streaming/non-streaming uses the correct branch.
4) Make API version behavior explicit per invocation (e.g., output_version) and ensure streaming paths filter internal-only fields.Example (pattern):
def _get_request_payload(messages, *, stream: bool, output_version: str | None, tools=None):
# 1) validate/translate to wire format
messages = normalize_messages_for_provider(messages) # standard blocks/ids
if tools is not None:
ensure_tool_schemas_present(tools) # avoid provider/token-counter failures
# 2) explicit flags: avoid leakage into branching logic
kwargs = {"stream": bool(stream)}
# 3) explicit versioning: don’t rely on defaults
if output_version is not None:
kwargs["_output_version"] = output_version
payload = build_provider_payload(messages, **kwargs)
# 4) strip internal-only keys so they never reach the provider
payload.pop("_output_version", None)
return payload
This standard reduces brittle compatibility bugs where the same higher-level object behaves differently depending on hidden flags, streaming vs non-streaming paths, or provider-specific schema requirements.
Use names that communicate intent and framework semantics—especially for (a) schemas and (b) callback parameters whose names are used for injection/dispatch.
Standards:
state, runtime, request) rather than relying on positional arguments or renaming._self, _runtime) instead of adding suppression comments.MULTILINE, the name should not hide that nuance).Example (callback arg naming + unused naming):
from typing import Any
from langgraph.types import interrupt
def before_agent(state: Any, runtime: Any) -> dict[str, Any]:
# framework-injected names: keep as-is
return {"ok": True, "state": state, "runtime": runtime}
def before_agent_unused(runtime: Any, state: Any) -> dict[str, Any]:
# if intentionally unused, use underscore prefix
_ = state
return {"ok": True}
async def headless_coroutine(_config: Any, **kwargs: Any) -> Any:
# intentionally unused config -> underscore
return interrupt({"args": kwargs})
Applying this will reduce confusion in schema-driven tooling, prevent subtle runtime bugs caused by incorrect parameter names, and make behavior easier to understand during review.
When implementing error handling, ensure (1) failures are validated early or handled explicitly, (2) optional steps degrade gracefully, (3) cancellation/abort prevents unnecessary work, and (4) cleanup never masks the true result.
Practical rules: 1) Fail fast on invalid configuration
2) Use safe fallbacks when detection/lookup can be uncertain
3) Treat optional capabilities as non-fatal
4) Respect abort/cancellation as an explicit control flow
5) Preserve error precedence during cleanup
finally block.6) Don’t emit misleading secondary errors/warnings
Example (pattern):
async function runWithPreflightAndCleanup(opts: {
abortSignal?: AbortSignal;
envOverrides?: Record<string, string>;
}) {
if (opts.abortSignal?.aborted) {
throw Object.assign(new Error('Aborted'), { name: 'AbortError' });
}
const prev = new Map<string, string | undefined>();
let primaryError: unknown;
try {
// Preflight validation (fail fast)
const binary = opts.envOverrides?.COPILOT_BIN_PATH;
if (binary !== undefined && binary.trim() === '') {
throw new Error('COPILOT_BIN_PATH is set but blank');
}
// Optional step (non-fatal)
try {
await maybeOptionalStep();
} catch (err) {
logger.warn({ err }, 'optional_step_failed');
}
// Primary work
return await doPrimaryWork();
} catch (err) {
primaryError = err;
throw err;
} finally {
// Cleanup must not mask primary outcome
try {
if (opts.envOverrides) {
for (const [k, v] of Object.entries(opts.envOverrides)) {
if (prev.has(k)) {
const old = prev.get(k);
if (old === undefined) Reflect.deleteProperty(process.env, k);
else process.env[k] = old;
}
}
}
} catch (cleanupErr) {
logger.warn({ cleanupErr }, 'cleanup_failed');
// never replace/override primaryError
}
}
}
Apply caching only when it is safe, bounded, and correct:
1) Avoid unbounded method memoization
functools.lru_cache/cache directly on methods whose arguments can grow without a tight bound (risk of memory leaks). If you must cache, use a bounded cache (maxsize=...) or a different lifecycle.2) Invalidate caches on mutation
3) Don’t memoize trivial derivations
4) Ensure cache-related transformations preserve structure
5) Document cached-metric semantics
Example: invalidate cached schema on mutation
# Pseudocode illustrating the pattern
class Tool:
_SCHEMA_INVALIDATING_FIELDS = {"name", "description"}
def __init__(self):
self.__dict__["tool_schema"] = None
self.__dict__["_inferred_input_schema"] = None
def __setattr__(self, name, value):
if name in self._SCHEMA_INVALIDATING_FIELDS:
# Clear only the caches that depend on these fields
self.__dict__.pop("tool_schema", None)
self.__dict__.pop("_inferred_input_schema", None)
super().__setattr__(name, value)
Example: avoid unbounded method lru_cache
# Prefer bounded caching or per-instance cached_property when lifecycle is bounded.
# Avoid: @lru_cache on methods where keys can grow without bound.
from functools import cached_property
class Parser:
@cached_property
def _compiled_pattern(self):
import re
return re.compile(r"\d+\.\s([^\n]+)")
Do not perform blocking I/O or other long-running synchronous work on asyncio’s event loop (especially in async client construction). Offload to worker threads (e.g., asyncio.to_thread) and prefer lazy credential/platform resolution protected by an async lock.
Also, when canceling/ending streamed responses, ensure you deterministically close the local stream before issuing any remote cancel call, and structure async generator cleanup so sessions/resources are released even if iteration terminates early.
Example pattern (lazy thread offload + guarded resolution):
import asyncio
class AsyncClient:
def __init__(self, *, use_sigv4: bool):
self._use_sigv4 = use_sigv4
self._botocore_credentials = None
self._creds_lock = asyncio.Lock()
async def _get_credentials(self):
if not self._use_sigv4:
return None
if self._botocore_credentials is None:
async with self._creds_lock:
if self._botocore_credentials is None:
# Offload blocking credential lookup/refresh work.
self._botocore_credentials = await asyncio.to_thread(_get_default_credentials)
return self._botocore_credentials
async def _prepare_request(self, request):
creds = await self._get_credentials()
_sign_httpx_request(request, creds, region="us-east-1")
Example pattern (stream cancel ordering):
def cancel_stream(stream, cancel_api):
stream.close() # close local stream first
return cancel_api(stream.response_id)
Practical checklist:
__init__ or other event-loop threads.asyncio.to_thread (with appropriate fallback if needed for older Python versions).asyncio.Lock.finally (and recognize that if the caller never iterates, your cleanup may not run—design lifecycle accordingly).Treat any value that may be undefined/null (environment globals, optional stream handles, user config fields, optional IDs) as untrusted at the boundary. Use explicit checks/type guards instead of non-null assertions, and either omit invalid fields or return a deterministic safe failure—never let missing data crash module load or runtime.
Apply these patterns:
window/document usage with typeof ... !== 'undefined' and avoid computing exported constants at module load.child.stdout! / child.stderr!; guard for missing pipes and handle with a clear outcome.Example (safe guards):
function getOrigin(): string {
return typeof window !== 'undefined' ? window.location.origin : 'http://localhost:3737';
}
function safePipeToQueue(stream: NodeJS.ReadableStream | null | undefined) {
if (!stream) {
// deterministic safe failure path
return { ok: false as const, reason: 'missing_stream' };
}
// safe to attach listeners
return { ok: true as const };
}
function parseConfig(raw: Record<string, unknown>) {
const out: { model?: string } = {};
if (typeof raw.model === 'string') out.model = raw.model;
// drop invalid/unknown fields silently
return out;
}
This prevents null-reference crashes (SSR/tests), avoids fragile ! usage, and keeps the system robust against malformed inputs.
Enforce security for any code that turns user/config inputs into subprocess execution or permission settings.
Apply these rules: 1) Spawn safely
spawn(binary, args, ...) with an args array.2) Validate inputs that affect execution
existsSync)../.., basename mismatches; trim whitespace; report invalid entries instead of silently accepting).3) Make permission precedence unambiguous
4) Don’t rely on pre-parsing
extraArgs can’t bypass safety checks.Example (deny-wins + safe argv building):
function buildArgs({ prompt, config, nodeConfig, extraArgs }: any): string[] {
const args: string[] = ['-p', prompt];
const allow = new Set([...(config.allowTools ?? []), ...(nodeConfig?.allowed_tools ?? [])]);
const deny = new Set([...(config.denyTools ?? []), ...(nodeConfig?.denied_tools ?? [])]);
for (const t of deny) allow.delete(t); // deny wins
for (const t of allow) args.push(`--allow-tool=${t}`);
for (const t of deny) args.push(`--deny-tool=${t}`);
// extraArgs appended only after all security decisions are derived from final argv
args.push(...(extraArgs ?? []));
return args;
}
// Later: scan final argv for broad flags and warn; then spawn(binary, args, ...).
This reduces risks of command injection, path traversal/file misuse, and silent permission escalation.
Configuration should be treated as untrusted input: validate and normalize it, ignore unknown/invalid fields, and ensure user misconfiguration can’t crash initialization or produce misleading warnings. Also gate checks by what’s actually configured and implement a clear precedence order (env → explicit config → user paths → canonical defaults → PATH lookup) with platform-correct behavior.
Apply it like this:
typeof and only assigning known fields.where resolving shims) is correct.Example pattern (parser + guard):
export function parseTimeouts(raw: Record<string, unknown>) {
const out: { firstEventTimeoutMs?: number; processTimeoutMs?: number } = {};
const toFinitePositiveMs = (v: unknown) =>
typeof v === 'number' && Number.isFinite(v) && v > 0 ? Math.trunc(v) : undefined;
const first = toFinitePositiveMs(raw.firstEventTimeoutMs);
if (first !== undefined) out.firstEventTimeoutMs = first;
const proc = toFinitePositiveMs(raw.processTimeoutMs);
if (proc !== undefined) out.processTimeoutMs = proc;
return out;
}
function shouldCheckGhAuth() {
const hasGhToken = !!(process.env.GH_TOKEN || process.env.GITHUB_TOKEN);
const hasOtherForge = !!(process.env.GITEA_URL || process.env.GITLAB_URL);
return hasGhToken || !hasOtherForge; // skip GH warning for non-GH-only setups
}
When you stream a subprocess’s stdout/stderr into an async generator, treat process exit, stream end/close, abort, and timeout escalation as concurrent events that can race.
Coding standard
exit. The “last output” might still be buffered when exit fires. Listen for stream close/end (or the streams’ close) and only then yield the final result/exit chunk.unref() escalation timers so they don’t keep the worker alive.exit happens before stdout/stderr stream end to ensure the final chunk is yielded only after buffers are flushed.Example pattern (simplified)
// shared queue
const { push, next } = makeEventQueue();
let processExited = false;
let stdoutClosed = false;
let stderrClosed = false;
const killProcess = (reason: string) => {
if (processExited) return;
child.kill('SIGTERM');
// escalation timer: track + clear + unref
if (sigkillTimer) clearTimeout(sigkillTimer);
sigkillTimer = setTimeout(() => {
if (!processExited) child.kill('SIGKILL');
}, 2000);
sigkillTimer.unref();
};
pipeLinesToQueue(child.stdout!, 'stdout', push);
pipeLinesToQueue(child.stderr!, 'stderr', push);
child.once('exit', (code, signal) => {
processExited = true;
push({ kind: 'exit', code, signal });
});
// Finalize only when streams are closed/flushed
child.stdout?.once('close', () => { stdoutClosed = true; push({ kind: 'stdout_close' } as any); });
child.stderr?.once('close', () => { stderrClosed = true; push({ kind: 'stderr_close' } as any); });
// consumer: drain events, then yield result when both close + exit known
// (implementation depends on your result-yield strategy)
Applying this prevents lost tail output, double-yields, and subtle leaks/hangs caused by concurrent lifecycle events and uncleared timers.
When multiple authentication tokens are supported (e.g., generic GitHub tokens vs Copilot-specific tokens), enforce a deterministic, documented precedence and require explicit opt-in for fallback behavior.
Apply this to CI/workflows and any code that selects credentials:
COPILOT_GITHUB_TOKEN).GH_TOKEN / GITHUB_TOKEN if the caller explicitly opts in (e.g., useLoggedInUser:false).Example (workflow logic pattern):
# Pseudocode: enforce precedence
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
# Selection rule (conceptual):
# if COPILOT_GITHUB_TOKEN set -> use it
# else if GH_TOKEN/GITHUB_TOKEN set -> require explicit useLoggedInUser:false
# else -> fail
This prevents accidental use of the wrong credentials, reduces risk of unexpected permissions, and makes security-sensitive behavior consistent across environments.
When adding or extending client/provider integrations, enforce a single, predictable configuration-resolution contract:
api_version, region), accept an explicit argument, otherwise fall back to the corresponding environment variable(s). Only raise a clear error when neither is provided.base_url derived from region), then copy()/cloning/overrides must recompute or correctly forward dependent values so behavior matches the updated config.copy() clears/normalizes incompatible fields instead of forwarding stale state.__init__.py), update the generator configuration so the change persists across automated releases.Example patterns:
# 1) Env fallback + clear error
resolved_api_version = api_version or os.environ.get("OPENAI_API_VERSION")
if not resolved_api_version:
raise ValueError("Must provide api_version or set OPENAI_API_VERSION")
# 2) copy(): keep dependent config consistent
new_region = region or self._region
# ensure base_url is recalculated when region changes
_forward_base_url = {} if region else {"base_url": self.base_url}
# 3) copy(): normalize mutually-exclusive auth fields
# if switching to api_key, drop credential provider
forwarded_credential_provider = None if "api_key" in kwargs else (credential_provider or self._credential_provider)
Add unit tests that cover:
region → base_url),When adding caching, ensure (1) correctness via validity/refresh and (2) safety via bounds/staleness resistance.
TTL - margin).def token_provider(*, token_duration: int = 3600):
_cached = [None]
_refresh_at = [0.0]
def generate() -> str:
# local signing; no network
return "bedrock-api-key-..."
def get() -> str:
import time
now = time.monotonic()
if _cached[0] is None or now >= _refresh_at[0]:
_cached[0] = generate()
_refresh_at[0] = now + max(token_duration - 60, token_duration * 0.9)
return _cached[0]
return get
functools.lru_cache(maxsize=...)) or a bounded LRU/size-capped cache.from functools import lru_cache
@lru_cache(maxsize=128)
def get_type_adapter(type_):
# expensive instantiation avoided
return make_adapter(type_)
api_key), either:
When handling failures or optional data, make the decision exactly once and reuse the result everywhere.
Apply two concrete rules:
1) Normalize once, then use the normalized values for both validation and execution. Don’t validate one set of fields and execute using separately-fallbacked canonical fields.
2) Centralize optional-feature degradation. Don’t repeat broad try/except import patterns across many call sites—move them into a shared helper that returns either the real implementation or a safe no-op.
Example (canonicalize before validate/execute):
def normalize_tool_request(payload: dict) -> tuple[str, dict] | None:
# pick a single canonical source-of-truth (fallbacking happens only here)
tool_name = payload.get("tool_name") or payload.get("tool")
tool_args = payload.get("tool_args") or payload.get("args")
if not tool_name or tool_args is None:
return None
return tool_name, tool_args
async def process_tools(self, msg: str):
tool_request = extract_tool_request(msg) # returns dict or None
if tool_request is None:
return
normalized = normalize_tool_request(tool_request)
if normalized is None:
return # structural/misformat handled once
tool_name, tool_args = normalized
await self.validate_tool_request({"tool_name": tool_name, "tool_args": tool_args})
# execution uses tool_name/tool_args derived from the same normalized result
await self.execute_tool(tool_name, tool_args)
Example (centralize optional integration):
# python/helpers/state_monitor.py
def get_state_monitor():
try:
from python.helpers.state_monitor_impl import StateMonitor
return StateMonitor()
except ImportError:
return None # safe degraded mode
# call site
monitor = get_state_monitor()
if monitor is not None:
monitor.state_push(...)
This prevents inconsistent “validation passes but execution breaks” flows and reduces duplicated, inconsistent error-handling paths for optional integrations.
When implementing non-trivial algorithms (graph ordering, batching under constraints, multi-pass transformations), apply four requirements:
1) Guarantee termination with explicit guards/invariants
2) Respect real constraints with dynamic computation
MAX_TOKENS_PER_REQUEST), batch using dynamic per-item measurements (e.g., token counts), not fixed-size assumptions.3) Keep behavior deterministic across passes
4) Separate algorithm concerns into a dedicated, testable unit
Resolver/Planner with small methods and a clean public interface (e.g., resolve(middleware)).Example (token-aware batching with progress and guaranteed exit):
# Precondition: token_counts and tokens are aligned
batched = []
i = 0
while i < len(tokens):
batch_end = i + 1 # progress guarantee
batch_token_count = token_counts[i]
for j in range(i + 1, min(i + _chunk_size, len(tokens))):
if batch_token_count + token_counts[j] > MAX_TOKENS_PER_REQUEST:
break
batch_token_count += token_counts[j]
batch_end = j + 1
# API call uses tokens[i:batch_end]
response = client.create(input=tokens[i:batch_end], **client_kwargs)
batched.append(response)
i = batch_end
Example (deterministic Mermaid node label encoding):
def to_safe_ascii_id(label: str) -> str:
out = []
for ch in label:
if ch.isascii() and (ch.isalnum()):
out.append(ch.lower())
else:
out.append('n' + format(ord(ch), 'x'))
slug = ''.join(out)
return slug if slug[0].isalpha() else 'n' + slug
Adopting these rules reduces correctness regressions (limits/termination), avoids subtle identity mismatches in graph-like structures, and makes algorithmic code easier to reason about and test.
When a test uses process-global/irreversible module mocking, prevent cross-test contamination by isolating the affected test files into separate bun test runs (batch isolation). Keep mocks narrowly scoped so tests don’t need to mock large dependency graphs, and avoid importing “config/provider” chains in units where tests shouldn’t require them.
Practical checklist:
mock.module() for the exact dependency that causes nondeterminism (e.g., config derived from developer machine).bun test <file> (or separate script/job) rather than grouping.Example (pattern):
// conversations.test.ts
mock.module('../config/config-loader', () => ({
loadConfig: mock(async () => ({ assistant: 'claude' })),
}));
Then run it as an isolated invocation:
cd packages/core && bun test packages/core/src/db/conversations.test.ts
This ensures your tests remain deterministic and don’t break due to local .archon/config.yaml contents or prior mocked state from other test files.
When working with LLM/chat “auxiliary” content (reasoning, tool calls/results, structured content blocks, and usage/metadata), enforce structural invariants so provider/streaming/truncation logic can’t silently corrupt meaning.
Practical rules:
tool_calls as the source of truth for tool-result validity; never emit/keep ToolMessages without a matching tool call, and avoid “reverse orphaning” when truncating/summarizing (keep the requesting AIMessage and its ToolMessages together atomically).chunk_position="last" semantics) so parsers can finalize partial JSON/tool arguments correctly.invoke vs batched generations)—index into LLMResult consistently.output_token_details or response_metadata when extra keys aren’t supported.Example (reasoning normalization + preserving empty semantics):
from typing import Any
def normalize_reasoning(reasoning: Any) -> str | None:
if reasoning is None:
return None
if isinstance(reasoning, str):
return reasoning # preserve ""
if isinstance(reasoning, list):
if not reasoning: # empty list => None
return None
parts: list[str] = []
for item in reasoning:
if isinstance(item, dict):
# support multiple provider shapes
v = item.get("thinking") if "thinking" in item else item.get("content")
parts.append("" if v == "" else str(v) if v is not None else str(item))
else:
parts.append(str(item))
return "\n".join(parts)
return str(reasoning)
Apply the same “invariant-first” mindset to tool-call/tool-result pairing and streaming chunk finalization: write code so the internal model never allows impossible states (or it is corrected immediately), and back it with targeted tests.
When coding against LLM providers, treat model capabilities and prompt/tool formats as spec-driven interfaces: match upstream expectations exactly, and avoid ad-hoc mappings or manual edits that can drift.
Apply this as three concrete rules: 1) Don’t hand-edit generated AI registries
models.generated.ts), update inputs/metadata at the source and regenerate via the build/generation script.2) Map “thinking/effort” (and similar) levels per model without collapsing semantics
xhigh) to a different one (e.g., max) unless the provider spec indicates they are equivalent.Example pattern:
function mapThinkingLevelToEffort(modelId: string, level: string) {
if (level !== "xhigh") return level;
// Example: Opus 4.7 distinguishes xhigh vs max.
const isOpus47 = ["opus-4-7", "opus-4.7"].some(s => modelId.includes(s));
return isOpus47 ? "xhigh" : "max";
}
3) Match provider prompt/tool syntax exactly (use the same tag structure)
Example pattern:
function buildSkillsSection(skills: string[]): string {
if (skills.length === 0) return "";
const body = skills.join("\n");
return `<available_skills>\n${body}\n</available_skills>`;
}
Net effect: fewer “it works for some models” surprises, less drift between code and provider reality, and safer changes when providers add/alter capabilities.
Keep codebase structure and import usage aligned with the intended architecture and boundaries.
src/features/shared/), rather than leaving them in a generic utils/ folder when the architecture expects otherwise.import type.Example:
// ✅ type-only import to avoid unused/runtime imports
import type React from 'react';
// ✅ do not import values you never use
// import { useToast } from '../contexts/ToastContext'; // remove if unused
When working with concurrency (threads/async), ensure code is safe under parallel invocations and does not block or re-enter running event loops.
Rules: 1) Eliminate shared mutable state across requests/threads
2) Be event-loop safe
asyncio.run()/loop.run_until_complete() when a loop may already be running.3) Provide and test async behavior
4) Keep async detection consistent
inspect.iscoroutinefunction over asyncio.iscoroutinefunction for newer Python/mypy compatibility.Example patterns:
# 1) Immutability / no post-init mutation
class ConditionalModelSettingsMiddleware(AgentMiddleware):
def __init__(self, conditions: list[tuple[Callable, dict[str, Any]]]):
super().__init__()
self._conditions = list(conditions) # don’t mutate after init
# 2) Offload blocking work from async contexts
async def abefore_agent(self, state, runtime):
return await run_in_executor(None, self.before_agent, state, runtime)
# 3) Don’t use asyncio.run() inside possibly-running event loops
# Prefer: make the validation async, or detect running loop and schedule appropriately.
async def _avalidate(...):
...
# then in async contexts: await _avalidate(...)
# 4) Prefer inspect for coroutine-function checks
import inspect
if ignore_condition_name is None or not getattr(handler, ignore_condition_name):
event = getattr(handler, event_name)
if inspect.iscoroutinefunction(event):
...
Adopting these practices prevents race conditions, avoids event-loop reentrancy problems, and ensures concurrency-heavy logic is correct under real async/parallel workloads.
Favor readability and maintainability by keeping functions/methods short, extracting complex logic into well-named helpers, and avoiding duplicated or closure-based implementations in constructors.
Apply these rules:
__init__ as closures; create private methods (or module-level functions) and wire them in from __init__.TYPE_CHECKING blocks).Example (extracting complex logic into helpers):
def _merge_reasoning_details(details: list[dict[str, Any]]) -> list[dict[str, Any]]:
if len(details) <= 1:
return details
merged: list[dict[str, Any]] = []
i = 0
while i < len(details):
entry = details[i]
if not _is_mergeable_fragment(entry):
merged.append(entry)
i += 1
continue
entry_type, entry_index, text_key = _fragment_key(entry)
base = _fragment_base(entry, text_key)
texts = [_fragment_text(entry, text_key)]
i += 1
while i < len(details) and _matches_fragment(details[i], entry_type, entry_index):
texts.append(details[i].get(text_key, "") or "")
base = _merge_fragment_metadata(base, details[i], text_key)
i += 1
merged.append({**base, text_key: "".join(texts)})
return merged
When adding or changing API-like functions (parsers, clients, helpers), treat them as having a stable contract: define the accepted inputs and exact output shape, cover tricky edge cases with regression tests, and remove/deprecate superseded code paths so the API surface stays unambiguous.
How to apply:
Example (contract + regression):
// Contract: treat GitHub URLs as { url } and local/UNC paths as { path }
function getCodebaseInput(input: string): { url?: string; path?: string } {
// ...implementation
return {};
}
// Regression cases for gaps
test('treats relative paths as paths', () => {
expect(getCodebaseInput('../repo')).toEqual({ path: '../repo' });
});
test('treats UNC paths as paths', () => {
expect(getCodebaseInput('\\server\\share\\repo')).toEqual({
path: '\\server\\share\\repo',
});
});
Checklist:
Don’t trust “sandboxed” templating when any part of template text (or dangerous expressions) can be influenced by an untrusted party. For security-sensitive code, assume Jinja2 (and similar template engines) is dangerous with untrusted inputs and enforce strict trust boundaries.
Apply this rule:
Example (safe pattern: allowlisted templates; user data only as inert values):
from jinja2 import Template
ALLOWED_TEMPLATES = {
"welcome": "Hello {{ name }}!",
}
def render_welcome(template_id: str, user_name: str) -> str:
# Block attacker-controlled templates
if template_id not in ALLOWED_TEMPLATES:
raise ValueError("Unknown template")
tmpl = Template(ALLOWED_TEMPLATES[template_id])
# Treat user_name as inert data; ensure it’s escaped for your output context
return tmpl.render(name=user_name)
If your system needs to accept user-provided templates, require additional hardening and security review rather than assuming Jinja2 sandboxing is sufficient.
When building or calling API client code, follow the SDK’s actual request/response types and conventions instead of assuming REST/dict semantics.
Apply these rules:
GenerateContentRequest), access fields using the proto/object APIs (e.g., request.contents) rather than dict helpers like .get(). This avoids runtime errors and preserves correct request shaping."/v1" or force versioned endpoints when the SDK manages its own endpoint construction. Prefer passing base_url=None (or the SDK default) so internal path logic remains correct.limit where related functions accept it), so callers have a stable contract across providers.Example (proto field access + SDK-managed endpoint):
from typing import Any
# Assume `request` is a proto/typed object created by the SDK
def inject_fields(request: Any) -> Any:
# Proto repeated composite field: iterate directly; do not use request.get(...)
for content in request.contents:
for part in content.parts:
# mutate request parts as required by the API
pass
return request
# When initializing provider clients, let the SDK handle endpoint construction
base_url = None # e.g., instead of hardcoding /v1
When transforming data to/from the API, always implement the backend’s explicit contract: ordering invariants, exact serialization, correct parsing by response format/content-type, endpoint-appropriate headers, and backend-specific URL/auth/version rules.
Apply these checks consistently:
api_type.Example (response-format-safe parsing + invariant-preserving payload building):
def get_response_input_items(response):
# preserve required reasoning->assistant consecutive pairing
items = []
for output_item in response.output:
items.append(output_item.model_dump(exclude_unset=True))
return items
def parse_response(rbody: str, headers: dict[str,str], response_format):
if response_format == "json" or headers.get("Content-Type") == "application/json":
return json.loads(rbody)
return rbody # text/srt/vtt
Rule of thumb: if the contract can be stated as “must be ordered X”, “must be JSON vs text Y”, or “must send header key Z / URL path P”, encode it as logic + validation—not as an assumption.
When working in async-capable code, ensure correctness and concurrency safety:
1) Keep async code truly async (no accidental sync calls)
await _async_transform_recursive(...), not the synchronous equivalent).2) Make shared caches/thread-safety explicit
3) Prevent event-loop blocking from blocking IO
Example pattern (bounded blocking + caching):
import os
from functools import lru_cache
@lru_cache(maxsize=1)
def _infer_region() -> str:
aws_region = os.environ.get("AWS_REGION")
if aws_region:
return aws_region
import boto3 # may do blocking config/FS access
return boto3.Session().region_name
Also ensure parity between sync/async clients: if an async client exposes the same configuration surface as sync, apply the same changes and keep behavior consistent.
Adopt a style rule that keeps code (1) concise in data derivation, (2) consistent in input normalization, and (3) correct in conditional logic by using the right source of state.
How to apply:
Example pattern:
from typing import Dict, List, Tuple
ModelOption = Tuple[str, str]
ProviderModeOptions = Dict[str, List[ModelOption]]
MODEL_OPTIONS: ProviderModeOptions = {...}
def get_known_models() -> Dict[str, List[str]]:
# Concise derived-data construction
return {
provider: sorted({value for options in mode_options.values() for _, value in options})
for provider, mode_options in MODEL_OPTIONS.items()
}
def _ensure_str(v) -> str:
# Centralized normalization for serialization/write paths
if v is None:
return ""
if isinstance(v, list):
return "\n".join(map(str, v))
return str(v)
def write_text(path, content):
with open(path, "w", encoding="utf-8") as f:
f.write(_ensure_str(content))
Checklist:
Any install/setup instructions and scripts must avoid common supply-chain and remote execution risks, and must clearly communicate the security posture.
Apply these rules:
@latest for critical packages). Prefer pinned versions.curl | bash). If you must support it, require explicit opt-in and add a user-visible warning.SECURITY.md and clear README guidance) that names the risks (supply chain, persistence) and states the safer install direction.Example (safer install guidance):
# BAD: remote execution default
curl -fsSL https://example.com/install.sh | bash
# BETTER: pinned artifact + explicit execution step
# (Version is pinned; fetching is logged and execution is explicit)
VERSION='1.2.3'
curl -fsSL -o tool.tgz "https://example.com/tool-${VERSION}.tgz"
# verify checksum/signature here, then extract/run explicitly
tar -xzf tool.tgz
./tool --help
Result: fewer opportunities for compromised dependencies or tampered install scripts to affect users, plus clearer expectations for safe setup.
When implementing tool-using LLM agent nodes (e.g., LangGraph/LangChain multi-agent flows), standardize a “tool loop → finalize only when tools are done” contract.
What to do
tools list.ChatPromptTemplate with a strong system_message that includes a coordination stop signal (e.g., FINAL PREDICTION: **YES/NO**) and any required output formatting instructions (e.g., “append a Markdown table”).partial(...) (at minimum: tool_names, current_date/trade date, market_id, market_question).chain = prompt | llm.bind_tools(tools)result = chain.invoke(state["messages"])report only when len(result.tool_calls) == 0 (because the graph will re-invoke the node after tools complete).Example pattern
def agent_node(state, llm):
current_date = state["trade_date"]
market_id = state["market_id"]
market_question = state["market_question"]
tools = [get_news, search_markets]
system_message = (
"You are a <Role> for prediction markets..."
" If you or any other assistant has the FINAL PREDICTION: **YES/NO**"
" prefix your response with FINAL PREDICTION: **YES/NO** so the team knows to stop."
" Make sure to append a Markdown table at the end of the report."
)
prompt = ChatPromptTemplate.from_messages([
("system", "... {tool_names}...\n{system_message}"
" For your reference, the current date is {current_date}."
" Market ID: {market_id}. Question: {market_question}"),
MessagesPlaceholder(variable_name="messages"),
])
prompt = prompt.partial(
system_message=system_message,
tool_names=", ".join([t.name for t in tools]),
current_date=current_date,
market_id=market_id,
market_question=market_question,
)
chain = prompt | llm.bind_tools(tools)
result = chain.invoke(state["messages"])
report = ""
if len(result.tool_calls) == 0: # finalize only when tools are complete
report = result.content
return report
Secondary process rule: Keep changes focused—don’t remove or refactor upstream/shared code in the same PR as an unrelated feature; move housekeeping to a separate PR.
When adding error handling for failure scenarios (infinite/looping behavior, retries, or other unbounded processes), ensure two things:
1) Normalize/validate error-relevant inputs before they affect control flow.
math.inf) must be converted to safe integer bounds before using constructs like range().2) Make raised exceptions actionable.
Example pattern:
import math
import sys
def retry_loop(max_retries):
if max_retries is math.inf or max_retries >= sys.maxsize:
range_limit = sys.maxsize
else:
range_limit = int(max_retries) + 1
for _ in range(range_limit):
yield
def detect_potentially_infinite_compaction(threshold):
# ... if two consecutive compactions happen:
raise RuntimeError(
"Potentially infinite compaction detected. "
f"Increase the compaction threshold (current: {threshold}) to avoid two consecutive compaction iterations."
)
Apply this standard so exceptions don’t just fail— they guide the fix and avoid additional crashes caused by invalid/edge inputs.
When designing API client/runner behavior, ensure the contract is explicit, state-driven, and aligned with what the server actually supports.
Apply these rules:
enum as primitives/literals; don’t invent transformations for unsupported composite/object literals).Example (state-driven follow-up request):
# BAD: reusing container id from a previous API response
# container_id = last_api_response.container.id
# GOOD: use container id from the current last assistant message in state
message = self._get_last_message()
if message.container is not None:
container_id = message.container.id
# use container_id for the next tool/assistant step
Example (explicit config with env default):
def get_auth_headers(api_key: str | None = None) -> dict[str, str]:
key = api_key or os.getenv("AWS_BEARER_TOKEN_BEDROCK")
if not key:
raise ValueError("Missing api key")
return {"Authorization": f"Bearer {key}"}
When adding/changing tests, optimize for (1) clear intent, (2) stability against refactors, and (3) determinism.
Practical rules:
set/dict conversions without sorting).autouse) for repeated setup/teardown patterns like forcing a fresh module import.Example: readable, stable expectation
result = convert_to_openai_function(MyModel)
assert result == {
"name": "MyModel",
"parameters": {"type": "object", "properties": {}, "required": []},
"strict": True,
}
Example: avoid brittle intermediate-step tests (assert the actual SDK call)
client = MagicMock()
# arrange llm to use mocked client
llm.invoke("hello", prompt_cache_key="k")
called_kwargs = client.create.call_args.kwargs
assert called_kwargs["prompt_cache_key"] == "k"
Example: fix nondeterministic ordering
items = list(set(items)) # flaky
items = sorted(set(items)) # deterministic
When writing or updating API skill docs, treat documentation as an operational dependency: prefer the most up-to-date source, keep docs self-contained, and make examples unambiguous.
Apply these rules: 1) Prefer live indexed documentation (MCP) when available
search_documentation exists, use it as the only doc source.../...). Use stable full paths or inline the required guidance.frame, document the expected type/encoding (e.g., bytes, base64 string, MIME type, tensor) so developers can pass correct inputs.Example (self-contained documentation snippet):
# `frame` must be raw bytes for a single image frame, encoded as JPEG/PNG bytes
# (or provide the required mime_type for the SDK wrapper).
# If you pass base64 strings, convert them to bytes (or use the SDK's expected field type).
await session.send_realtime_input(
video=types.Blob(data=frame_bytes, mime_type="image/jpeg")
)
Use this checklist during review to prevent stale guidance, broken links, and “works in theory” examples that fail at integration time.
When building Gemini/LLM integrations, always use the most current and indexed API documentation/spec first, and avoid inefficient fallback behaviors.
Apply this standard:
search_documentation is available: treat it as the only documentation source.
search_documentation, read the returned docs, and then generate code immediately.llms.txt after MCP already provided sufficient information.llms.txt) to discover pages, then fetch only the specific needed pages.gemini-api-dev skill examples.Example (MCP-first behavior):
IF tool search_documentation exists:
docs = search_documentation("How to call Structured Outputs in Gemini")
// Ensure docs are sufficient
generate code using docs
// Do NOT fetch llms.txt as a fallback
ELSE:
fetch llms.txt index
fetch only the needed page(s)
generate code using fetched docs
When wiring state/functions, avoid implicit access through window.*/globalThis. Use explicit ES module imports so code is deterministic and loads correctly, and keep code in the module/plugin that owns it.
Apply this standard
window (including Alpine root store patterns).window.Alpine?.store(...) and globalThis bridging for core dependencies; replace with imports.Example (store access)
// Prefer this:
import { createStore } from "/js/AlpineStore.js";
import { store as notificationStore } from "/components/notifications/notification-store.js";
// Avoid this pattern:
// const rootStore = window.Alpine?.store ? window.Alpine.store("root") : undefined;
// ...then rely on root/global wiring
Checklist
window.Alpine.store('root') just to get runtime state that has a dedicated module.globalThis TODOs persisting long-term for dependencies—replace with imports.When inputs or response fields are optional/nullable, preserve their semantics explicitly and avoid unsafe coercion or indexing.
Apply these rules:
1) Don’t coerce None with bool(...) when None has distinct meaning. If you mean “unset,” omit the field/parameter rather than converting it.
2) Don’t blindly index into dicts/JSON (obj["key"]) when keys may be missing; use obj.get("key", default) (often {}) to prevent exceptions.
3) When building request artifacts (e.g., headers), only include values when the input is actually present; otherwise, send an empty structure or omit the header.
Example patterns:
# 1) Tri-state optional: None => omit
payload = {}
if by_alias is not None:
payload["by_alias"] = by_alias # preserve None-vs-explicit
# 2) Safe dict access
error_data = response.data.get("error", {})
message = error_data.get("message", "Operation failed")
# 3) Conditional auth header
headers = {} if not api_key else {"Authorization": f"Bearer {api_key}"}
Result: fewer runtime KeyErrors/invalid requests, and correct behavior when upstream defaults/configuration rely on “unset” vs “explicit value.”
Adopt a single documentation standard: every docstring/comment should (1) explain intent and observable behavior, (2) make responsibility/ownership explicit, (3) be traceable when tied to external or non-obvious defaults, (4) be safe when examples could do harm, and (5) follow established docstring conventions without duplicating type annotations.
Practical rules
int | str) or has special handling, document why and when the special case occurs.Example pattern
def _gpt5_defaults_to_no_reasoning(model: str) -> bool:
"""Return True if a gpt-5 variant defaults to reasoning_effort='none'.
Notes:
Source: See OpenAI GPT-5.2 Prompting Guide and GPT-5.2 model docs.
If OpenAI changes these defaults, update this helper and add a regression test.
Args:
model: Model identifier (e.g., 'gpt-5.2', 'gpt-5.2-pro').
Returns:
True when the model defaults to no reasoning.
"""
...
Applying this standard will make docs easier to maintain, reduce user confusion, and prevent unsafe or misleading copy/paste behavior.
Adopt a “type-safe, clean, DRY” style for readability and maintainability.
schema_param: ResponseFormatParam = {...}).Dict[str, str] for headers) rather than Any.# type: ignore when the mismatch can be fixed by correcting the related type(s).ParamSpec to preserve call signatures.Example (import + typed local + helper pattern):
# module scope
import json
def parse_stream_line(line: bytes) -> str:
if not line or line == b"data: [DONE]":
return ""
if hasattr(line, "decode"):
line = line.decode("utf-8")
if line.startswith("data: "):
line = line[len("data: "):]
return line
def parse_stream(rbody):
for line in rbody:
out = parse_stream_line(line)
if out:
yield out
def some_function() -> "ResponseFormatParam":
schema_param: "ResponseFormatParam" = {"type": "text"}
return schema_param
Applying these consistently will improve clarity (fewer surprises), maintainability (less duplication), and type-checker effectiveness (fewer ignores and safer refactors).
Use precise types instead of Any, and avoid unnecessary typing.cast by relying on type-guard utilities and existing type narrowing. In tests, prefer the concrete pytest types/fixtures (e.g., pytest.MonkeyPatch) over broad Any.
Apply this as a style rule:
Any when a concrete type exists.typing.cast purely to satisfy typing after runtime checks, prefer type-guard helpers (e.g., is_dict, is_list) that narrow types.Example:
import pytest
import typing as t
from .typing_utils import is_dict, is_list
@pytest.mark.respx()
def test_something(monkeypatch: pytest.MonkeyPatch) -> None:
...
def _deep_merge_extra_fields(existing: object, new: object) -> object:
if is_dict(existing) and is_dict(new):
# type is narrowed by is_dict
for k, v in new.items():
...
return existing
if is_list(existing) and is_list(new):
# type is narrowed by is_list
existing.extend(new)
return existing
return new
Write tests that are (a) high-signal and not fragile, and (b) structured with standard pytest mechanisms.
Apply:
pytest.MonkeyPatch.context() (or equivalent) to ensure patches clean up at the right scope.pytest.mark.skipif(...) instead of early-return branches.Authorization).Example (focused assertion + fixture-friendly structure):
import re
import pytest
import respx
import httpx
from unittest.mock import Mock
@pytest.mark.respx()
def test_bearer_token_env_passes_authorization(monkeypatch: pytest.MonkeyPatch, respx_mock):
respx_mock.post(re.compile(r"https://bedrock-runtime\.us-east-1\.amazonaws\.com/model/.*/invoke")).mock(
return_value=httpx.Response(200, json={"ok": True})
)
monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "test-bearer-token")
# exercise code that triggers the request
# sync_client.messages.create(...)
calls = list(respx_mock.calls)
assert len(calls) == 1
assert calls[0].request.headers.get("Authorization") == "Bearer test-bearer-token"
This approach keeps tests reliable, maintainable, and valuable as the code evolves.
When building WebUI plugin/extension systems, treat the backend as the source of truth for (1) resolving extension contents and (2) providing a stable context schema to JS extensions.
Apply these rules:
Extension-point resolution: When the client finds an element like <x-extension id="...">, it should call a dedicated backend API (e.g., get_webui_extensions(id)) that searches the plugin roots by convention (e.g., .../extensions/webui/{id}/*.html) and returns the HTML/content to paste into that node. Keep the client loader thin; avoid re-implementing manifest/scan logic when the backend can resolve by id.
Stable context schema: Ensure callJsExtensions(..., context) uses one unified “context” shape across default and custom message handlers. If an extension needs message.no (log number), that field must be present consistently in the default implementation too.
Example (contract-driven usage):
// Client: paste extension HTML resolved by backend
async function applyExtensionPoint(node, id) {
const htmlParts = await get_webui_extensions(id); // backend contract
node.innerHTML = htmlParts.join("\n");
}
// JS extension: rely on unified context schema
export default async function injectBranchButtons(context) {
const msgs = context?.messages;
if (!Array.isArray(msgs) || msgs.length === 0) return;
for (const m of msgs) {
// contract requires log number (no)
if (typeof m.no !== "number") throw new Error("Missing context.messages[].no");
// ...use m.no to wire actions
}
}
Outcome: frontend extension code becomes deterministic (no “sometimes field is present” surprises), and plugin authors can build against a predictable backend-defined contract.
When a value can be missing/null, reflect it in the type system and handle it explicitly at the boundary—never leak None into observable outputs (yields, dict keys, metadata, merged content) and don’t “paper over” missing invariants with synthetic placeholders.
Practical rules:
1) Prefer X | None = None (or Optional[X]) over sentinel-literals like Literal[False] for optional callables.
2) Guard before writing/using: if something derived could be None (e.g., a dict key), check before assignment.
3) Ensure iterators/streaming never yield None as a valid element unless the type says so.
4) Keep semantic distinctions: e.g., treat args=None as “streaming in-progress” and args={} as “completed no-args” to avoid parsing/execution bugs.
5) If an invariant is violated (e.g., “an AIMessage must exist”), either raise a clear error or widen the function signature and make callers handle the missing case—don’t create dummy objects that hide the underlying state bug.
Example patterns:
from typing import Callable
# 1) Optional callable
length_fn: Callable[[list[str]], list[int]] | None = None
# 2) Guard None-derived keys
header_key = splittable_headers.get("#" * depth)
if header_key is not None:
current_chunk.metadata[header_key] = value
# 3) Avoid yielding None
first_chunk = await first_map_chunk_task
if first_chunk is not None:
yield first_chunk
# 4) Preserve streaming vs final semantics
# args=None => not ready to execute; args={} => execute with no args
if tool_call_args is None:
# streaming/in-progress
pass
else:
# final state
run_tool_with(tool_call_args)
# 5) Missing invariant: raise or widen types (don’t fabricate)
if last_ai_message is None:
raise ValueError("Expected at least one AIMessage in state")
When multiple modules need the same state/config/schema (e.g., context variables like timezone, or prompt search paths), do not replicate those fields or the logic that derives them in several places. Instead, funnel access through a single abstraction and reuse shared utilities.
How to apply:
subagents.get_paths(..., include_plugins=True)) instead of building paths in multiple call sites.Example (pattern):
# Instead of each module reading/handling timezone separately,
# make snapshot the source of truth.
# snapshot.py
@dataclass
class SnapshotContext:
timezone: str
# ...other shared fields
def build_context_from_snapshot(snapshot: Any) -> SnapshotContext:
return SnapshotContext(timezone=snapshot.timezone)
# state_sync_handler.py
ctx = build_context_from_snapshot(snapshot)
state_monitor.mark_dirty(sid, reason=reason, timezone=ctx.timezone)
# Or, if StateMonitor only stores projection fields,
# accept an object built from snapshot rather than individual scalars.
This reduces “adjust multiple scripts when fields change” and keeps code organization consistent while improving readability.
When exposing data to the client, treat shared/global values and plugin routes as explicit API surface:
1) Don’t publish global client/window state by sprinkling ad-hoc dictionaries into multiple unrelated API handlers. Instead, use one centralized mechanism:
index.html (e.g., next to globalThis.gitinfo), orExample (centralized injection):
<script>
// after globalThis.gitinfo
globalThis.runtimeInfo = {
isDevelopment: {{ runtime.is_development() | tojson }}
};
</script>
2) Plugin endpoints must be mounted under a stable namespace to prevent collisions with core API routes.
/plugins/<plugin_name>/...Example (route mounting concept):
# core router bootstrap
register_routes(prefix=f"/plugins/{plugin_name}", handlers=plugin_handlers)
When working with nullable/optional values, treat None (absence) differently from other falsy values like "" (empty string) or 0 (zero). Use explicit is not None checks when empty values are valid, and avoid repeating null checks after you’ve already established a non-null invariant via an early return/guard.
Apply it like this:
if x is not None: over if x: when x may be an empty string/zero but should still be considered “present”.None, don’t add redundant x is not None guards later.Example:
import os
bearer = os.getenv("AWS_BEARER_TOKEN_BEDROCK")
# Empty string is a valid value, so check for None (absence), not truthiness.
if bearer is not None:
headers["Authorization"] = f"Bearer {bearer}"
# Later, avoid redundant None checks after a guard/early return:
if response is None:
return
if response.get("content"):
append_messages(message, response)
Do not commit secret keys, credentials, or signing material to source code or public repos. Store secrets in environment variables or a managed secret store, load them at runtime, and ensure they are not present in repository history. Design signed tokens so that the server validates them and they are short-lived, and have a plan to rotate/revoke keys if exposure occurs.
Why: a secret embedded in code (e.g., SECRET_KEY used to HMAC-sign tokens) can be extracted and used to forge or replay tokens even if tokens have expirations. Removing secrets from code reduces attack surface and supports secure key management.
How to apply:
OLD: SECRET_KEY = “dfc92bc5e95825103283f01c2aa6ca7fe7f6ffc31778ea82c354785c73b0858c”
NEW: import os SECRET_KEY = os.environ.get(“MERCH_SECRET_KEY”) # set via env or secret manager if not SECRET_KEY: raise RuntimeError(“MERCH_SECRET_KEY not configured”)
Checks/PR guidance:
References: [0]
When introducing identifiers that represent external/domain data (e.g., tool calls, event payloads) and shared utilities, keep naming and placement semantically aligned and avoid redundant typing.
Apply: 1) Use domain-consistent suffixes for schema-derived types
event.input, prefer *Input (e.g., BashToolInput) over *Params/*Parameters unless the rest of the codebase uses a different established convention.2) Prefer inference over duplicated/hand-written boundary types
execute/handler boundary if the type is already inferred.3) Put shared utilities in accurately named modules and reuse them
shell.ts rather than shell-config.ts if it’s not config-only).Example (adapted):
const bashSchema = Type.Object({
command: Type.String(),
timeout: Type.Optional(Type.Number()),
});
// Domain-aligned: matches event.input
export type BashToolInput = Static<typeof bashSchema>;
// Inference-first: avoid re-specifying the same structure if already inferred
export const createBashTool = () =>
({
execute: async (
_toolCallId: string,
{ command, timeout }, // type inferred from bashSchema
signal?: AbortSignal,
) => {
// ...
},
});
Rule of thumb: if the identifier communicates “input/payload”, name it accordingly; if the logic is shared, name the module for what it provides and reuse it rather than duplicating/relocating ad-hoc helpers.
When using React hooks that interact with external systems (browser events, subscriptions, async requests), write code so it cannot leak resources or update state after the component unmounts.
Standard
useEffect, always return a cleanup function that removes listeners/subscriptions.useEffect (fetch, timers, requests), cancel/abort on cleanup (e.g., AbortController) so setState can’t run after unmount.useSyncExternalStore over manual event subscription logic.Example (safe effect + abort)
function Notifications() {
const [data, setData] = useState<Notification[]>([])
useEffect(() => {
const controller = new AbortController()
const onResize = () => {
// listener logic
}
window.addEventListener('resize', onResize)
fetch('/api/notifications', { signal: controller.signal })
.then(r => r.json())
.then(next => setData(next))
.catch(() => {
/* ignore abort */
})
return () => {
window.removeEventListener('resize', onResize)
controller.abort()
}
}, [])
return <div />
}
Example (subscription preference)
resize) via listeners, consider modeling that external value with useSyncExternalStore rather than ad-hoc addEventListener + setState patterns.When doing algorithmic equality checks for arrays where order doesn’t matter (multiset equality), avoid (a) mutating the input with .sort() and (b) sort+join/stringify approaches when a linear-time counting strategy is available. Use a non-mutating sort (toSorted) only if sorting is truly the chosen approach; otherwise prefer counting maps (expected O(n) in common JS engines) to avoid O(n log n) sorting.
Example (order-insensitive multiset equality):
function hasChanges(current: string[], original: string[]) {
if (current.length !== original.length) return true;
const counts = new Map<string, number>();
for (const x of current) counts.set(x, (counts.get(x) ?? 0) + 1);
for (const x of original) {
const c = counts.get(x) ?? 0;
if (c === 0) return true;
if (c === 1) counts.delete(x);
else counts.set(x, c - 1);
}
return counts.size !== 0;
}
If you must use sorting for comparison, use a non-mutating method:
return current.toSorted().join() !== original.toSorted().join();
Avoid direct console.log/console.warn (and other console.*) in application code—especially in TUI/interactive flows—because it can break rendering and other runtime behavior. Route all log/diagnostic output through the project’s logging/UI abstraction so messages are formatted and displayed consistently.
Apply this rule by:
console.* calls with the existing notification/logging mechanism (e.g., uiContext.notify(message, level) or a centralized logger).info, warn, error) in the chosen API.Example (pattern):
// Bad (don’t do this)
console.warn("[pi-ai] Skipping unsigned thinking block");
// Good
uiContext.notify("Skipping unsigned thinking block", "warn");
If a function currently falls back to console.log when UI isn’t available, refactor it to use an injected logger (or a non-TUI-safe abstraction) instead of writing to the console directly.
Use the lock to protect shared mutable state during mutations, but avoid holding it for read-side convenience/field-by-field getters.
Rules
logs[], updates[], notifications[]).Example pattern (commit under lock, transform outside)
def update_item(self, *, no: int, heading: str | None, content: str | None):
# Preprocess outside the lock
if heading is not None:
new_heading = _truncate_heading(self._mask_recursive(heading))
if content is not None:
item_type = self.logs[no].type # or pass in required type explicitly
new_content = _truncate_content(self._mask_recursive(content), item_type)
with self._lock:
item = self.logs[no]
if heading is not None:
item.heading = new_heading
if content is not None:
item.content = new_content
self.updates.append(item.no)
Applying this standard will reduce lock contention, prevent unnecessary refactors tied to read-side locking, and still keep shared writes thread-safe.
Cache behavior should be justified by real reuse and measured impact.
Apply this standard: 1) Scope the cache correctly: for per-process/per-session data, prefer in-memory caching and avoid disk persistence unless it measurably reduces recomputation time on restart/resume. 2) Make eviction policy explicit: if you use a bounded Map/Set, document whether eviction is FIFO, LRU, etc., and why that policy fits the observed access pattern. 3) Size caches based on evidence: verify whether the cache is actually populated and whether larger sizes improve hit rate/latency; don’t pick sizes “because it seems fine.” 4) Define acceptable cold-start behavior: if cache misses on resume are minor and the system already recomputes shortly, it’s fine to start empty.
Example pattern (in-memory, bounded, explicit FIFO):
const CACHE_LIMIT = 512;
const cache = new Map<string, number>();
function getOrCompute(key: string, compute: () => number) {
const v = cache.get(key);
if (v !== undefined) return v;
const next = compute();
if (cache.size >= CACHE_LIMIT) {
const firstKey = cache.keys().next().value; // FIFO eviction
if (firstKey !== undefined) cache.delete(firstKey);
}
cache.set(key, next);
return next;
}
If you need different behavior (e.g., true LRU), use an LRU structure or maintain recency explicitly—don’t assume insertion-order eviction matches your intent.
When building AI/LLM-related tooling (tool-calls, background execution, inference/image generation), enforce compatibility at the boundaries:
1) Use team-standard LLM-friendly IDs
guids.py helper and its default length (e.g., 8). Don’t invent new ID formats for tool-call correlation.2) Make AI hardware initialization conservative + always fall back
Example (ID generation pattern):
# pseudo-example: use the team helper rather than custom UUID strings
from python.helpers.guids import llm_guid # assumed name from your guids.py
call_id = llm_guid(length=8) # keep the default length consistent
Checklist to apply during review
Default rule: in performance-sensitive code, prevent hidden blowups and avoid expensive work being executed repeatedly in hot paths or on import.
Apply this checklist: 1) Replace inefficient primitives inside loops
pop(0) or sort() on each iteration.collections.deque or heapq where applicable.2) Don’t do global scans per iteration in graph/ordering logic
3) Cache expensive introspection/metadata
inspect.signature) or other typing-introspection, compute it once when wiring middleware/handlers, store it, and reuse it during request processing.4) Prefer lazy, memoized loading over eager initialization
__init__ paths; delay until actually needed and memoize results.5) Choose fast strategies by default (when the API is designed for it)
Example (dependency resolution):
from collections import deque
# Build reverse deps once: dep -> set(dependents)
reverse_deps = {}
for cls, deps in dep_graph.items():
for dep in deps:
reverse_deps.setdefault(dep, set()).add(cls)
queue = deque(sorted([c for c in instance_by_class if in_degree[c] == 0], key=lambda x: x.__name__))
while queue:
current = queue.popleft()
for dependent in reverse_deps.get(current, ()): # only affected neighbors
in_degree[dependent] -= 1
if in_degree[dependent] == 0:
queue.append(dependent)
When resolving dependencies or other derived configuration, never “log-and-continue” into an inconsistent internal state.
Apply this standard:
depends_on (types/contents) in AgentMiddleware.__init__() so errors point to the middleware that provided bad input.TypeError/ValueError from constructor/args). Avoid broad except Exception.warning/error (or raise) rather than DEBUG-only logs so failures are actionable in real runs.Example pattern (inspired by the discussed failure mode):
instance_by_class: dict[type, Middleware] = {}
try:
instance_by_class[dep_class] = dep_class() # auto-instantiation
except TypeError as e: # narrow expected failures
# Fail fast with context; do not `continue` and later risk KeyError
raise ValueError(
f"Failed to auto-instantiate middleware dependency {dep_class.__name__} "
f"required by {type(instance).__name__}: {e}"
) from e
# Safe access: only when guaranteed present
dep_instance = instance_by_class[dep_class]
This prevents delayed, confusing errors (like KeyError) and ensures failures are reported with precise, fixable context.
Documentation should be kept authoritative and maintainable: use stable links, avoid recommending deprecated APIs, and remove misleading/ineffective documentation details.
Apply it as follows:
tool.invoke(...)) rather than agent-creation workflows.default that provides no value in JSON Schema).Example (tool-only, non-deprecated usage):
from langchain_desearch.tools import DesearchTool
tool = DesearchTool()
result = tool.invoke({"query": "LLM RAG best practices"})
print(result)
When designing or extending APIs, treat existing “core” interface contracts as stable and enforce exact compatibility (method signature + parameter semantics + return shapes) across base classes and all implementations. If you need different inputs/behavior for a subset of modules, add an adapter/compatibility layer in the business layer instead of changing the core interface.
Practical rules:
retrieve(self, input: Any) -> Tuple[Graph, Any]) so implementations can accept different input forms while still conforming to the contract.Example: adapter-based compatibility (don’t modify core)
# Core interface (unchanged)
class ChatPromptTemplate:
def generate_input_values(self, *, question: str, **kwargs):
...
# Business-layer adapter
class ChatDashboardPromptTemplate(ChatPromptTemplate):
def generate_input_values(self, *, input: str, **kwargs):
# map new variable name to old core contract
return super().generate_input_values(question=input, **kwargs)
Example: contract-consistent retriever base
from typing import Any, Tuple
class GraphRetrieverBase:
async def retrieve(self, input: Any) -> Tuple["Graph", Any]:
raise NotImplementedError
# Implementation conforms to the base signature
class DocumentGraphRetriever(GraphRetrieverBase):
async def retrieve(self, input):
# input can be Union[Graph, List[str], List[List[float]]] in practice
graph = ...
extra = None
return graph, extra
This prevents runtime failures like “takes N positional arguments but M were given” and avoids breaking unrelated modules that depend on the core contract.
When configuration is moved/renamed or when settings are derived from environment variables, ensure (1) the dotenv loader points to the correct file path/name and (2) there is an explicit precedence order for derived settings (env-provided values override generated/default values).
Apply this as two concrete checks:
.env (or stop using default.env), update the code that resolves the env file path (e.g., avoid loaders that still call something like get_abs_path('.env') when the new location is usr/.env or similar). Also remove references to env filenames you don’t actually use.create_* or other defaults.Example pattern:
import dotenv
def apply_settings(copy: dict) -> None:
# precedence: env override > generated default
external_key = dotenv.get_dotenv_value("A0_EXTERNAL_API_KEY")
if external_key:
copy["mcp_server_token"] = external_key
else:
copy["mcp_server_token"] = create_auth_token()
Any service exposed to the network (e.g., via Docker ports) must be protected with authentication, and any secret used for that auth (e.g., Jupyter token/password) must come from environment variables (e.g., .env) rather than being hardcoded in versioned files. If a compose file uses placeholder defaults, treat them as non-production scaffolding and require production overrides.
Example (secure pattern):
services:
jupyter:
ports:
- "8888:8888"
env_file:
- .env
environment:
# Put the real token in .env (do not commit it)
- JUPYTER_TOKEN
command: >-
jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root
--ServerApp.token='${JUPYTER_TOKEN}'
Checklist:
.env (or a secret manager), not in the compose file.changeme) are clearly non-production and never deployed as-is.Use explicit existence checks rather than value-based null checks, and be intentional about failing fast versus providing defaults for missing data.
When checking for optional data, prefer checking for key/attribute existence rather than checking if values are truthy or greater than zero. This prevents subtle bugs where legitimate zero values or empty strings are treated as missing data.
For missing required data, prefer explicit KeyError/AttributeError over None-based error handling to provide clearer error messages and fail fast.
Prefer explicit existence checks:
# Good - check if key exists
if "cacheReadInputTokens" in usage:
attributes["cache_read_tokens"] = usage["cacheReadInputTokens"]
# Avoid - value-based check that excludes valid zero values
if usage.get("cacheReadInputTokens", 0) > 0:
attributes["cache_read_tokens"] = usage["cacheReadInputTokens"]
Fail fast for required data:
# Good - explicit KeyError for missing required field
status=Status(data["status"])
# Avoid - None handling that masks the real issue
status=Status(data.get("status")) # Will fail with confusing None error
Be intentional about defaults:
# Good - explicit defaults for optional fields with clear intent
usage = Usage(**{"inputTokens": 0, "outputTokens": 0, "totalTokens": 0, **event.get("usage", {})})
# Consider defensive checks only when inheritance/overrides make them necessary
if not hasattr(self, "session_type"):
self.session_type = SessionType.AGENT
Choose names that clearly convey purpose and intent rather than generic or ambiguous terms. Names should be specific enough to understand functionality without requiring additional context.
Avoid generic names:
utils, helpers, or base when more specific alternatives existclass Executor, use class ConcurrentExecutor or class SequentialExecutorutils.py with specific names like validation.py or formatting.pyUse semantically meaningful names:
serialize_state() and deserialize_state() instead of ambiguous alternativesnext_nodes_to_execute (plural) instead of next_node_to_execute when referring to multiple itemstimeout instead of timeout_seconds when accepting a timedelta objectChoose appropriate specificity:
get_agent_card() instead of the vague _discover_agent_card()name_override instead of the verbose agent_facing_tool_nameoutput_type instead of structured_output_type when the context makes “structured” redundantExample:
# Avoid generic names
class Executor: # Too generic
pass
# Use descriptive names
class ConcurrentToolExecutor: # Clear purpose and scope
def serialize_state(self) -> dict: # Clear action
pass
def get_next_nodes(self) -> list[str]: # Clear return type
pass
This approach improves code readability and reduces the need for additional documentation to understand component purposes.
Ensure all classes, methods, and properties have comprehensive docstrings that clearly explain their purpose, behavior, and usage. Docstrings should be preferred over inline comments for method descriptions and should include:
Example of comprehensive docstring:
class MultiAgentBase(ABC):
"""Base class for multi-agent helpers.
This class integrates with existing Strands Agent instances and provides
multi-agent orchestration capabilities.
Attributes:
id: Unique identifier for the multi-agent instance
"""
@property
def system_prompt(self) -> str | None:
"""Get the system prompt as a string.
Returns the system prompt content converted to string format,
while system_prompt_content accepts various content types.
Returns:
String representation of system prompt, or None if not set
"""
def __init__(self, config_source: str | dict[str, any]):
"""Initialize AgentConfig from file path or dictionary.
Args:
config_source: Either a file path (with 'file://' prefix) or
a dictionary containing agent configuration.
Expected shape: {
"name": "agent_name",
"model": "model_name",
"tools": ["tool1", "tool2"],
"system_prompt": "prompt text"
}
"""
This approach improves code maintainability and helps future contributors understand the codebase without needing to read implementation details or PR discussions.
When implementing persistence and resume functionality in durable execution systems, ensure that state is persisted at consistent event boundaries and that resume logic handles all execution states explicitly to maintain deterministic behavior.
Key principles:
Choose appropriate persistence timing: Persist state at events that provide clear recovery semantics. For example, persisting on BeforeNodeCallEvent ensures that if execution crashes during a node, resume will restart from that node rather than an earlier point.
Handle terminal states explicitly: When resuming from terminal states (COMPLETED, FAILED), determine whether to restart execution or return previous results based on clear business logic.
Avoid state corruption during resume: Don’t automatically clear failed nodes or modify execution state during resume unless there’s explicit justification, as this can alter the original execution path.
Example of proper state handling:
def deserialize_state(self, payload: dict) -> None:
# Handle terminal states explicitly
if payload.get("status") in (Status.COMPLETED.value, Status.FAILED.value):
if not payload.get("next_nodes_to_execute"):
# Execution ended - reset for new run
self._reset_state()
return
# Resume from persisted state without modifying execution path
self._restore_state(payload)
# Don't clear failed_nodes - preserve original execution semantics
This ensures that durable execution systems behave predictably across interruptions and restarts, maintaining the integrity of the workflow orchestration.
Select the correct synchronization mechanism based on your execution context and avoid unnecessary synchronization overhead. In async contexts with coroutines, locks are often unnecessary since coroutines run cooperatively in a single thread. Use asyncio.Lock() for async contexts and threading.Lock() for multi-threaded scenarios. When bridging sync and async code with threads, ensure proper context variable propagation and use daemon threads for background tasks.
Key guidelines:
asyncio.Lock() when coordinating async tasks, threading.Lock() for thread coordinationExample of proper lock selection:
# Async context - lock usually unnecessary
async def process_nodes_async(self, nodes):
# Coroutines run cooperatively, no race conditions
for node in nodes:
self.state.completed_nodes.add(node)
# Mixed async/thread context - use asyncio.Lock
class GraphExecutor:
def __init__(self):
self._lock = asyncio.Lock() # For async task coordination
async def execute_parallel(self, nodes):
async with self._lock: # Only if truly needed
# Critical section
pass
# Thread context - use threading.Lock
class FileManager:
def __init__(self):
self._lock = threading.RLock() # For thread coordination
def write_file(self, data):
with self._lock:
# Thread-safe file operations
pass
Before adding synchronization, verify you actually have a race condition. Many async operations don’t require explicit locking due to the cooperative nature of coroutines.
When updating project configuration (e.g., pyproject.toml), ensure dependency declarations match how packages are actually used: align requires-python with dependency-supported Python versions, keep dev-only tooling in dev-dependencies, and use extras for optional features instead of adding new required runtime deps. Also, set minimum versions based on the concrete APIs/helpers you rely on.
Apply this checklist:
Python>=X, set requires-python to at least >=X (don’t claim broader support than your deps allow).dev-dependencies, not dependencies.openai[cli]) and load them safely at the call site.>= versions when the features you use are introduced/changed in newer upstream releases.Example (optional CLI dependency):
# pyproject.toml
[project.optional-dependencies]
cli = ["argcomplete>=1.12.0"]
# _cli.py
try:
import argcomplete # type: ignore
except ImportError:
argcomplete = None
if argcomplete is not None:
# use argcomplete
...
else:
# either disable CLI niceties or show a message
...
Use clean, simple patterns when accessing configuration values with defaults. Avoid redundant fallback operations and overly complex boolean conversions that reduce code readability.
Prefer simple .get() with defaults:
# Good: Clean and readable
"stream": self.config.get("streaming", True)
# Good: Method already returns appropriate default
all_tools_config = self.tool_registry.get_all_tools_config()
# Good: Simple default parameter
session_type: SessionType = SessionType.AGENT
Avoid redundant fallbacks:
# Avoid: Unnecessary `or {}` when method returns dict
all_tools_config = self.tool_registry.get_all_tools_config() or {}
# Avoid: Overly complex boolean conversion
"stream": bool(self.get_config().get("streaming", True))
This pattern improves code maintainability by reducing complexity and making default behavior explicit. When methods already guarantee return types (like returning empty dict), additional fallbacks create confusion about the actual contract. Keep configuration access patterns simple and trust documented method behaviors.
Write robust test assertions that verify complete objects and behaviors rather than individual properties. Use pytest’s built-in features for exception testing and mock verification to make tests more reliable and maintainable.
Key practices:
pytest.raises(ExceptionType, match="expected message") instead of manual exception handlingcall_args instead of manual parameter capturingExample of improved assertions:
# Instead of manual exception handling:
try:
some_function()
raise AssertionError("Expected an exception")
except ValueError as e:
assert "expected message" in str(e)
# Use pytest.raises with match:
with pytest.raises(ValueError, match="expected message"):
some_function()
# Instead of checking individual properties:
assert agent.messages[1]["role"] == "user"
assert "toolResult" in agent.messages[1]["content"][0]
assert agent.messages[1]["content"][0]["toolResult"]["toolUseId"] == "orphaned-123"
# Assert the complete structure:
expected_message = {
"role": "user",
"content": [{"toolResult": {"toolUseId": "orphaned-123", ...}}]
}
assert agent.messages[1] == expected_message
# Instead of manual kwargs capturing:
def capture_kwargs(*args, **kwargs):
capture_kwargs.captured_kwargs = kwargs
# Use mock verification:
assert mock_function.call_args == call(expected_args, **expected_kwargs)
This approach makes tests more readable, catches more potential issues, and reduces the likelihood of false positives in test results.
When modifying public APIs, always preserve backwards compatibility to avoid breaking existing consumers. Public methods, even if rarely used directly, must maintain their existing signatures and behavior.
Use these patterns to evolve APIs safely:
Add new methods instead of modifying existing ones:
# Instead of changing invoke_callbacks() to async
def invoke_callbacks(self, event: TInvokeEvent) -> tuple[TInvokeEvent, list[Interrupt]]:
# Keep existing sync method
async def invoke_callbacks_async(self, event: TInvokeEvent) -> tuple[TInvokeEvent, list[Interrupt]]:
# Add new async method, deprecate old one
Use parameter separators for new optional parameters:
# Backwards compatible - new params after *
def __call__(
self, prompt: AgentInput = None, *,
structured_output_type: Type[BaseModel] | None = None,
**kwargs: Any
) -> AgentResult:
Avoid @abstractmethod for new interface methods:
# Breaking - forces all implementers to update immediately
@abstractmethod
def new_method(self): pass
# Non-breaking - allows gradual adoption
def new_method(self):
raise NotImplementedError("Subclasses should implement this method")
Preserve import paths when reorganizing:
# In __init__.py - maintain old import while moving implementation
from .new_location import convert_pydantic_to_tool_spec
Consider the impact on all consumers, including those calling public methods directly, extending abstract classes, or using specific import paths. When in doubt, add new APIs alongside existing ones rather than modifying them.
When implementing new behavior behind feature flags or configuration (paths, env vars, index dimensions, toggles like text2gql), use centralized, documented config instead of hardcoded values or scattered env access.
Apply these rules: 1) No absolute paths/constants in code: resolve paths from config/env (with sensible defaults). 2) Use feature flags from config and keep them consistent across code/docs/.env.template. 3) Avoid “parameter explosion”: encapsulate related settings into a dedicated *Config object and pass that object (or access via get_config()) instead of threading many constructor args. 4) Don’t read os.getenv in feature logic; normalize env->config during config building. 5) Don’t hardcode tunables (e.g., embedding/index dimension); pull them from config. 6) Keep layer boundaries: app-layer settings (e.g., CFG/proxy/app-specific knobs) should be passed down as explicit parameters/config, not embedded in lower modules.
Example (replace absolute paths with config):
from pathlib import Path
from dataclasses import dataclass
@dataclass
class DataManusConfig:
db_path: str
excel_path: str
def load_config() -> DataManusConfig:
# normalize env in one place (not throughout business logic)
import os
return DataManusConfig(
db_path=os.getenv("DATA_MANUS_DB_PATH", "./examples/test_files/datamanus_test.db"),
excel_path=os.getenv("DATA_MANUS_EXCEL_PATH", "./examples/test_files/employer_info.xlsx"),
)
def build_connector(cfg: DataManusConfig):
db_file = Path(cfg.db_path).expanduser().resolve()
return SQLiteConnector.from_file_path(str(db_file))
Checklist for each PR:
Design security mechanisms with configurable behavior to handle different threat scenarios and use cases. Avoid rigid, one-size-fits-all security implementations that may not suit all deployment contexts.
Security controls should provide configuration options that allow teams to adjust behavior based on their specific threat model. For example, a content filtering system might need different redaction strategies - sometimes redacting only the violating content, other times redacting both input and output to prevent cascading security issues.
# Good: Configurable security behavior
def _has_blocked_guardrail(self, guardrail_data: dict[str, Any]) -> tuple[bool, bool]:
blocked_input = any(self._find_detected_and_blocked_policy(assessment)
for assessment in input_assessment.values())
blocked_output = any(self._find_detected_and_blocked_policy(assessment)
for assessment in output_assessments.values())
return blocked_input, blocked_output
# Configuration allows different redaction strategies:
# - guardrail_redact_input: redact only input violations
# - guardrail_redact_output: redact only output violations
# - Both: redact both when either triggers (prevents cascading issues)
This approach enables security controls to adapt to different scenarios, such as preventing assistants from echoing trigger words that could create security loops, while still allowing targeted redaction when appropriate.
When implementing CI checks that can block pull request merges, always provide clear override mechanisms for exceptional cases. Hard-failing CI checks should be strong signals to developers, but teams need escape hatches when legitimate exceptions arise.
Design your CI workflows to fail meaningfully while maintaining flexibility:
# Example: PR size check with override capability
- name: Check PR size
run: |
if [ $TOTAL_CHANGES -gt 1000 ]; then
echo "PR is too large ($TOTAL_CHANGES lines). Please split into smaller PRs."
echo "To override, add 'override-size-check' label and provide justification."
exit 1
fi
Key considerations:
This approach provides strong developer guidance while acknowledging that exceptional cases requiring large PRs will occasionally arise and need a path forward.
Identify and consolidate duplicate code patterns by extracting common logic into reusable functions and unifying similar code blocks. This improves maintainability, reduces bugs, and enhances readability.
Key strategies:
Example from the codebase:
# Before: Duplicate code paths
if self.node_timeout is not None:
events = self._stream_with_timeout(...)
else:
events = self.stream_async(...)
# After: Unified approach
events = self._stream_with_timeout(...) if self.node_timeout else self.stream_async(...)
Another example:
# Before: Complex inline construction
after_event = agent.hooks.invoke_callbacks(
AfterToolCallEvent(
agent=agent,
tool_use=tool_use,
result={
"toolUseId": tool_use["toolUseId"],
"status": "cancelled",
"content": [{"text": "Tool execution was cancelled"}]
}
)
)
# After: Extract result construction
cancelled_result = self._create_cancelled_tool_result(tool_use)
after_event = agent.hooks.invoke_callbacks(
AfterToolCallEvent(agent=agent, tool_use=tool_use, result=cancelled_result)
)
Always look for opportunities to consolidate when you notice similar patterns, repeated logic, or multiple code paths that achieve the same outcome.
Always throw exceptions for error conditions rather than silently failing, logging warnings, or attempting fallback behavior that masks underlying problems. When encountering unexpected states, missing required data, or configuration errors, raise descriptive exceptions immediately rather than continuing execution with degraded functionality.
This principle prevents bugs from being masked and ensures developers receive clear feedback about problems in their code. Silent failures make debugging difficult and can lead to unexpected behavior in production.
Examples of what to avoid:
# Bad: Silent failure with warning
try:
saved = self.session_manager.read_multi_agent_json()
except Exception as e:
logger.warning("Skipping resume; failed to load state: %s", e)
return # Silently continue without state
# Bad: Fallback that masks the real problem
def serialize_node_result(self, raw):
if hasattr(raw, "to_dict"):
return raw.to_dict()
# Fallback for strings and other types
return {"agent_outputs": [str(raw)]} # Masks unknown types
Preferred approach:
# Good: Explicit failure with clear message
try:
saved = self.session_manager.read_multi_agent_json()
except Exception as e:
raise RuntimeError(f"Failed to load session state: {e}") from e
# Good: Fail fast on unknown types
def serialize_node_result(self, raw):
if hasattr(raw, "to_dict"):
return raw.to_dict()
if isinstance(raw, dict):
return raw
raise TypeError(f"Cannot serialize node result of type {type(raw)}")
The goal is to make problems visible immediately so they can be addressed rather than allowing them to propagate silently through the system.
Keep code simple, direct, and well-organized by avoiding unnecessary complexity and properly structuring components. Remove redundant implementations when existing mechanisms already handle the functionality. Avoid indirect approaches when more straightforward solutions exist. Extract large components into separate files when they become unwieldy.
Examples of improvements:
updateSettings instead of additional setNodePath calls)attributes.type mapped to id rather than complex conditional chains)This approach improves code readability, reduces maintenance burden, and makes the codebase more intuitive for other developers to understand and modify.
Always use logging instead of print statements, and choose appropriate log levels to avoid log spam. Print statements can contaminate the stdio buffer and break system functionality, especially in server environments.
Use logging with appropriate levels:
logger.warning() for recoverable issues that need attention (e.g., encoding fallbacks)logger.debug() for detailed information that might be verboseExample of proper logging practices:
# Bad - using print statements
print("DEBUG: Starting terraform version detection...")
print(f"Elixir test repository already compiled in {repo_path}")
# Good - using appropriate logging levels
logger.debug("Starting terraform version detection...")
logger.info(f"Elixir test repository already compiled in {repo_path}")
# Good - warning for fallback scenarios
logger.warning(f"Could not decode {file_path} with encoding='{encoding}'; using best match '{match.encoding}' instead")
# Good - debug level for potentially verbose information
logger.debug(f"Skipping {path}: does not match include pattern {paths_include_glob}")
This prevents stdio buffer contamination and ensures logs are properly categorized and filterable.
Choose names that clearly convey purpose and intent rather than generic or ambiguous terms. Prefer specific, descriptive terminology that makes code self-documenting and reduces cognitive load for readers.
Key principles:
file_reader is more precise than content_reader when the function reads entire filescharset_normalizer.from_path is more meaningful than a bare from_path importIntEnum with named values instead of raw int for severity levelsExample improvements:
# Less clear
from charset_normalizer import from_path
def get_extracts(content_reader: Callable[[str], str]):
severity: int = 1
# More semantically meaningful
import charset_normalizer
def find_code_snippets(file_reader: Callable[[str], str]):
severity: DiagnosticSeverity = DiagnosticSeverity.ERROR
result = charset_normalizer.from_path(path)
This approach makes code more maintainable by reducing ambiguity and making the developer’s intent explicit through careful name selection.
When adding or modifying AI model configurations, ensure proper validation through both pattern-based matching and functional testing. Avoid hardcoding specific model IDs when existing patterns can handle multiple models generically. Always test model functionality before adding to production configurations.
For region-specific model handling, prefer pattern-based approaches:
// Instead of hardcoding each model:
if (isAustraliaRegion &&
(modelID.startsWith("anthropic.claude-sonnet-4-5") || modelID.startsWith("anthropic.claude-haiku-4-5"))) {
modelID = `au.${modelID}`
}
// Use existing patterns:
const modelRequiresPrefix = ["claude", "nova-lite", "nova-micro", "nova-pro"].some((m) =>
modelID.includes(m))
For model priority lists, verify functionality before deployment:
// Test each model before adding to priority list
const priority = ["llama3", "gemini-2.5-pro-preview", "codex-mini", "claude-sonnet-4"]
// Ensure models work beyond just the first request
This approach reduces maintenance overhead and prevents production issues with untested AI model configurations.
When working with streaming or TCP options, be explicit and defensive:
1) Closing streams: If you terminate a stream early (e.g., you don’t fully consume an HTTP/SSE iterator), ensure you close the underlying network resource—not just a wrapper/decoder that may not implement close().
2) Socket options: Set keepalive (and similar socket options) only when the platform exposes the needed constants, and use mutually exclusive conditionals to avoid configuring conflicting options.
Example pattern:
# 1) Stream termination: close the underlying response/connection
try:
# consume partially or stop early
...
finally:
# Prefer the actual HTTP response/connection close
if hasattr(response, "close"):
response.close()
elif hasattr(decoder, "close"):
decoder.close()
# 2) TCP keepalive: conditional and non-conflicting configuration
socket_options = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, True)]
TCP_KEEPINTVL = getattr(socket, "TCP_KEEPINTVL", None)
if TCP_KEEPINTVL is not None:
socket_options.append((socket.IPPROTO_TCP, TCP_KEEPINTVL, 60))
elif sys.platform == "darwin":
TCP_KEEPALIVE = getattr(socket, "TCP_KEEPALIVE", None)
if TCP_KEEPALIVE is not None:
socket_options.append((socket.IPPROTO_TCP, TCP_KEEPALIVE, 60))
Apply this standard to prevent leaked connections, hanging sockets, and platform-specific networking bugs.
When designing API responses that need to handle different data types or display states, maintain consistent JSON structure and use established encoding standards to preserve backward compatibility. Avoid changing response schemas that would break existing client integrations.
For binary data in JSON responses, use base64 encoding as the standard approach:
if (isBinary) {
const buffer = await bunFile.arrayBuffer().catch(() => new ArrayBuffer(0))
const content = Buffer.from(buffer).toString("base64")
return { type: "binary", content, mimeType: getMimeType(full) }
}
For displaying modified or discounted values, use additional fields or metadata rather than changing the core data structure. This allows clients to handle the information appropriately while maintaining the expected response format. The principle follows established practices like AWS S3’s JSON APIs, which use base64 encoding for binary content to ensure text-safe transmission within JSON payloads.
Design API interfaces to be simple and explicit rather than hiding complexity behind elaborate fallbacks or conditional logic. When core functionality is unavailable, fail explicitly with clear error messages instead of implementing complex workarounds. Push complexity and decision-making to the caller rather than embedding it within the API implementation.
Key principles:
Example of preferred approach:
# Good: Simple interface, explicit failure
def rename_symbol(self, file_path: str, line: int, column: int, new_name: str) -> WorkspaceEdit | None:
if not self.server.supports_rename():
raise UnsupportedOperationError("Language server does not support rename operations")
return self.server.send.rename(params)
# Good: Explicit assertions instead of conditionals
allow_symbol = next((s for s in symbol_list if s.get("name") == "allow"), None)
assert allow_symbol is not None, "allow symbol should always be found"
# Good: Simple interface pushes list creation to caller
def _run_command(command: list[str], logger: LanguageServerLogger, cwd: str) -> None:
# Caller is responsible for creating the command list
This approach makes APIs more predictable, easier to test, and clearer about their expectations and limitations.
Documentation should provide contextual guidance about when and why to use features, not just how to configure them. Additionally, strategically link to external documentation rather than duplicating content to reduce maintenance overhead.
When documenting configuration options or features:
Example of good contextual documentation:
## Azure URL Configuration
Different Azure deployments require different URL formats. Configure these options based on your deployment type:
| Deployment Type | useDeploymentBasedUrls | useCompletionUrls | Use Case |
|-----------------|------------------------|-------------------|----------|
| Standard API | false | false | Basic Azure OpenAI service |
| Custom Deployment | true | true | When using named model deployments |
For detailed Azure setup instructions, see the [official Azure OpenAI documentation](https://docs.microsoft.com/azure/cognitive-services/openai/).
This approach helps users understand not just what to configure, but when they need each configuration, while avoiding the maintenance burden of duplicating external documentation.
When integrating multiple AI model providers, implement proper abstraction layers to normalize differences in APIs, data formats, and behaviors. Different providers often have inconsistent interfaces that require careful handling to maintain application consistency.
Key practices:
Example from LiteLLM provider handling:
def _format_request_message_contents(self, role: str, content: ContentBlock) -> list[dict[str, Any]]:
"""Format LiteLLM compatible message contents.
LiteLLM expects content to be a string for simple text messages, not a list of content blocks.
This method flattens the content structure to be compatible with LiteLLM providers like Cerebras and Groq.
"""
# Provider-specific format conversion logic here
# Handle provider-specific error messages
LITELLM_CONTEXT_WINDOW_OVERFLOW_MESSAGES = [
"Context Window Error",
"Context Window Exceeded",
"Input is too long",
# Common error substrings from different providers
]
This approach prevents provider inconsistencies from breaking application logic and ensures consistent behavior across different AI model backends.
Ensure naming follows consistent patterns within the codebase and adheres to official framework conventions. When creating related types or functions, use matching naming schemes to maintain clarity and prevent synchronization issues. Prefer established conventions over custom variations unless there’s a compelling reason to deviate.
For example, if you have CloneRepoParams, create a corresponding CloneRepoReturnType rather than using a generic return type. Similarly, when working with frameworks like Supabase, stick to their official function-name/index.ts convention rather than implementing broader custom patterns.
// Good: Consistent naming pattern
interface CloneRepoParams { ... }
interface CloneRepoReturnType { ... }
// Good: Following official convention
// supabase/functions/my-function/index.ts
// Avoid: Inconsistent or custom naming
interface CloneRepoParams { ... }
interface GenericResponse { ... } // Should be CloneRepoReturnType
This approach reduces cognitive load, prevents naming conflicts, and ensures the codebase remains maintainable as it scales.
Tests should verify exact expected results rather than generic existence checks. Avoid assertions like isinstance(), len() > 0, is not None, or any() that only confirm something exists without validating correctness. Instead, assert for specific expected values, names, and properties.
Generic assertions are too weak and don’t catch real functionality issues:
# Weak - only checks existence
assert len(references) > 0
assert isinstance(symbols, list)
assert symbol is not None
# Strong - checks exact expected results
assert "greet" in symbol_names
assert references[0]["uri"].endswith("Main.scala")
assert symbol["name"] == "add"
assert symbol["kind"] == 12 # Function kind
This approach catches actual bugs in symbol detection, cross-file references, and language server functionality that generic checks miss. Focus on testing the specific symbols, files, and properties your code is supposed to find or produce. When testing language server functionality, verify that expected function names, type names, and file paths are present in results rather than just confirming non-empty responses.
Documentation should be comprehensive, clear, and provide all necessary context for understanding and using the code effectively. This includes several key aspects:
Explain complex implementations: When code uses non-standard approaches, tricks, or unexpected patterns, the docstring must explain what these are and why they’re necessary. For example, if implementing custom handlers, loops, or configuration file writing, document the reasoning behind these choices.
Use proper grammar and tone: Documentation should use correct English grammar and maintain a professional, accurate tone. Avoid subjective or potentially misleading language like “quick and dirty” when describing legitimate implementation approaches.
Include essential details: Provide complete parameter information including units, types, and constraints. For example, specify whether a timeout parameter is in seconds, milliseconds, etc.
Maintain consistency: Follow established documentation standards and formats that support examples and are compatible with documentation tools.
Example of good documentation:
def request_workspace_symbol(self, query: str, timeout: int = 30) -> Union[List[UnifiedSymbolInformation], None]:
"""
Request symbols across the workspace using the Language Server Protocol.
This method uses a custom retry mechanism with exponential backoff due to
server instability issues commonly seen with workspace symbol requests.
:param query: The search string to filter symbols by
:param timeout: Maximum wait time in seconds (default: 30)
:return: List of matching symbols, or None if request fails
"""
This approach ensures that future developers can understand both what the code does and why it was implemented in a particular way.
Always use exception chaining with raise ... from e when re-raising or wrapping exceptions to preserve the original error context and stack trace. This maintains debugging information and follows Python best practices for error propagation.
When catching and re-raising exceptions, avoid losing the original exception context. Exception chaining helps developers trace the root cause of errors through the entire call stack.
Example of proper exception chaining:
try:
project_config = ProjectConfig.from_yml(Path(project_file_path))
except Exception as e:
raise ValueError(f"Error loading project configuration from {project_file_path}: {e}") from e
Additionally, catch specific exception types rather than broad parent classes to avoid unintended behavior. For instance, catch PermissionError specifically rather than its parent OSError when you only want to handle permission issues.
Avoid over-decorating exceptions with unnecessary context when the original exception already contains sufficient information for debugging.
Before implementing custom tool installation steps in GitHub Actions workflows, check if there’s an existing setup action available on the GitHub Actions marketplace. Marketplace actions are typically more reliable, better maintained, and reduce workflow complexity compared to custom installation scripts.
When adding tool installation to your workflow, first search the marketplace for actions like setup-<tool> (e.g., setup-node, setup-python, setup-go). Only implement custom installation logic when no suitable marketplace action exists or when the existing action doesn’t meet your specific requirements.
Example of preferred approach:
# Preferred: Use marketplace action
- uses: actions/setup-node@v3
with:
node-version: '18'
# Avoid when marketplace alternative exists:
- name: Install Node.js manually
run: |
curl -fsSL https://nodejs.org/dist/v18.17.0/node-v18.17.0-linux-x64.tar.xz
# ... custom installation steps
This approach reduces maintenance burden, improves reliability, and leverages community-tested solutions.
When making configuration changes, balance technical best practices with developer workflow requirements and real-world usage scenarios. Configuration decisions should not only be technically sound but also support practical development needs.
Consider both immediate technical implications and broader workflow impact:
Example from pyproject.toml management:
# Keep dev dependencies for workflow continuity
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-asyncio>=1.0.0",
]
# Include dependencies that mirror customer usage patterns
dependencies = [
"strands-agents-tools>=0.2.0,<1.0.0", # Kept for realistic testing despite circular deps
]
Before removing or restructuring configuration elements, verify that the change won’t disrupt established developer workflows or compromise the realism of your testing environment.
When implementing expensive initialization operations that may be triggered concurrently, use a shared promise to coordinate multiple requests and prevent duplicate initialization. This pattern is especially important for operations like downloading dependencies, starting external processes, or establishing connections that take significant time to complete.
Store the initialization promise in a module-level variable and reuse it across concurrent calls. This ensures that multiple simultaneous requests will wait for the same initialization to complete rather than starting duplicate operations.
let jdtlsInit: Promise<ChildProcessWithoutNullStreams | undefined>
async spawn(root) {
// ... validation logic ...
if (jdtlsInit == null) {
jdtlsInit = initializeJdtls(java, root)
}
const jdtlsServer = await jdtlsInit
// ... use initialized resource ...
}
This approach prevents race conditions where “initialization could run twice or more” due to the time-consuming nature of the operation, and allows concurrent requests to “wait for concurrent initialization requests until the first one’s initialization is finished.”
Errors must be communicated through appropriate mechanisms for their execution context. In CLI applications, use proper exit codes to indicate error states (non-zero for failures). For shell command execution, implement proper error handling to prevent unexpected crashes and provide graceful failure modes.
For CLI tools, always set appropriate exit codes when errors occur:
if (err) {
spinner.stop("Upgrade failed", 1) // Exit code 1 for error
// ... handle error logging
}
For shell commands, use error handling mechanisms like .quiet().nothrow() to prevent crashes:
await $`curl -L -o '${archivePath}' '${releaseURL}'`.quiet().nothrow()
await $`tar -xzf ${archivePath}`.cwd(distPath).quiet().nothrow()
This ensures that errors are properly signaled to the appropriate layer (operating system, calling process, or user interface) and prevents silent failures or unexpected crashes.
Maintain consistent patterns across all API endpoints, including naming conventions, response structures, HTTP status codes, and interface design. This ensures a predictable and professional API surface that follows established conventions.
Key consistency requirements:
/end-users not /end_users, /context-variables not /context_variablesReadEvaluationResponse instead of returning internal DTOs directlyresponse_model everywhere or nowhere within the same moduleExample of consistent endpoint design:
@router.patch("/{customer_id}", response_model=CustomerDTO)
async def update_customer(params: CustomerUpdateParamsDTO) -> CustomerDTO:
# Returns 200 OK with updated entity
@router.get("/{evaluation_id}")
async def get_evaluation(evaluation_id: EvaluationId) -> ReadEvaluationResponse:
# Dedicated response DTO, not direct internal model
This prevents API fragmentation and reduces cognitive load for API consumers by establishing predictable patterns they can rely on across all endpoints.
When integrating AI libraries and SDKs, carefully manage dependencies by pinning versions with upper bounds to prevent breaking changes and minimize scope by implementing simple types locally when possible.
For version management, always specify upper bounds to avoid automatic consumption of breaking changes:
# Good: Pinned with upper bound
gemini = [
"google-genai>=1.32.0,<2.0.0"
]
# Avoid: No upper bound
gemini = [
"google-genai>=0.5.0"
]
For scope management, evaluate whether you truly need the full SDK or can implement simple components locally. Keep essential functionality like clients and error handling from the official SDK, but consider implementing basic types, enums, and configuration classes yourself to reduce dependency surface area. This approach balances functionality with dependency minimization while maintaining proper API communication and error handling.
Design API methods to accept parameter objects instead of individual parameters or complex optional fields. This approach makes interfaces more maintainable and flexible when requirements evolve, avoiding breaking changes when adding or removing fields.
Instead of destructuring parameters or using many optional fields:
// Avoid - breaks when parameters change
public async editCustomLanguageModelProvider({
id,
name,
apiKey,
baseUrl
}: {
id: string;
name?: string;
apiKey?: string;
baseUrl?: string;
}) {
return this.invoke("edit-provider", { id, name, apiKey, baseUrl });
}
// Avoid - complex optional schemas
export const ProviderSettingSchema = z.object({
apiKey: SecretSchema.optional(),
vertexProjectId: z.string().optional(),
azureEndpoint: z.string().optional(),
// ... many optional fields
});
Prefer parameter objects and proper type modeling:
// Better - stable interface that accepts parameter objects
editCustomLanguageModelProvider(params: EditCustomLanguageModelProviderParams) {
return this.invoke("edit-provider", params);
}
// Better - use unions for distinct parameter sets
export const ProviderSettingSchema = z.union([
RegularProviderSettingSchema,
VertexProviderSettingSchema,
AzureProviderSettingSchema
]);
This pattern keeps method signatures stable while allowing the parameter types to evolve independently.
When updating pyproject.toml (lint/type/dependency config), keep changes minimal and future-safe: enable/disable rules deliberately, scope suppressions to the smallest scope, avoid broad “select everything” patterns that can introduce unintended auto-fixes, remove redundant settings, and bound dependency versions.
Guidelines:
# noqa: <code> / noqa: <rule> on the specific line; avoid broad ignorelist entries unless truly pervasive.select = ["ALL"] without scoping how fixes are applied. If you must opt into many rules, ensure auto-fixing cannot silently change semantics or readability by pulling in newly-added rules after version bumps.Example (lint config):
[tool.ruff.lint]
# Prefer explicit lists or ALL only with careful fix scoping.
select = ["ALL"]
# AND ensure you only fix the rules you explicitly trust:
# fixable = ["F", "E", "W"] # example: opt-in only
[tool.flake8-builtins]
# Prefer per-line suppression over global ignores:
# "id" should usually be handled with: some_var = id(...) # noqa: A002
ignorelist = []
Example (mypy config):
[tool.mypy]
strict = true
# Avoid redundant flags like strict_bytes if strict already implies it.
# strict_bytes = true # remove
Example (dependency bounds):
dependencies = [
"langgraph>=0.6.0,<1.0.0",
]
Place all import statements at the top of the file as global imports rather than importing modules within functions or methods. Local imports reduce code readability, complicate dependency tracking, and can indicate poor code organization.
Why this matters:
How to fix: Move all imports to the top of the file, organized in the standard order: standard library, third-party packages, then local modules.
Example:
# Bad - local imports
def _setup_runtime_dependencies(cls, logger, config, settings):
import os # Should be at top
import platform # Should be at top
if platform.system() == "Windows":
# ...
# Good - global imports
import os
import platform
def _setup_runtime_dependencies(cls, logger, config, settings):
if platform.system() == "Windows":
# ...
Exceptions: Local imports are acceptable only in rare cases like:
In such cases, add a comment explaining why the local import is necessary.
Avoid mixing model-specific features with provider-level configuration or hard-coding model-specific logic in generic handlers. This creates architectural debt and maintenance burden as new AI models are added to the system.
Model-specific features (like thinking modes, specialized parameters, or model-unique behaviors) should be handled through dedicated model configuration layers rather than being embedded in provider settings or generic request handlers.
Example of what to avoid:
// DON'T: Model-specific config in provider schema
export const ProviderSettingSchema = z.object({
apiKey: SecretSchema.optional(),
// Model-specific feature mixed with provider config
enableFlashThinking: z.boolean().optional(),
});
// DON'T: Hard-coded model logic in generic handlers
if (selectedProviderId === "google" && selectedModelName === "flash-2.5") {
includeGoogleThoughts = settings.enableFlashThinking;
}
Instead, design model configuration to be modular and keep provider settings focused on provider-level concerns like authentication and endpoints. This approach scales better as new models with unique features are integrated.
Ensure AI model configurations accurately reflect official specifications and avoid hardcoded assumptions. Model parameters, token limits, capabilities, and naming should match vendor documentation rather than using generic defaults.
Key practices:
tokens: maxInput + maxOutput)default: 0.8 for strength)Example of proper model configuration:
{
description: 'Gemini 2.5 Flash 是 Google 最先进的主力模型',
displayName: 'Gemini 2.5 Flash', // Clear, consistent naming
id: 'google/gemini-2.5-flash',
contextWindowTokens: 1_048_576, // Verified against official docs
maxOutput: 65_535, // Separate input/output limits
// No hardcoded parameter defaults
}
This prevents user confusion, billing errors, and ensures reliable model behavior across different AI providers.
Ensure all public functions and classes have comprehensive docstrings that include parameter descriptions, type hints, return value documentation, and references to related implementations. This significantly improves usability by helping developers understand how to use APIs correctly and find related code.
Key requirements:
Optional[bool], List[str])Example:
def __init__(
self,
signature: Type["Signature"],
tools: list[Callable],
max_iters: Optional[int] = 5
) -> None:
"""
Initialize the ReAct module for reasoning and acting with tools.
Args:
signature: The signature defining input and output fields for the module.
tools: List of functions, callable classes, or dspy.Tool instances available to the agent.
max_iters: Maximum number of reasoning iterations to perform. Defaults to 5.
Example:
```python
react = dspy.ReAct(signature="question->answer", tools=[get_weather])
```
"""
This approach helps developers understand APIs without needing to read implementation code, reduces support burden, and improves overall developer experience.
Implement proper null safety patterns to prevent runtime errors and unexpected behavior. This includes several key practices:
1. Handle Optional types correctly: When working with Union types containing None, extract the non-None type before type checking to avoid issubclass() errors with type annotations.
def _strip_optional(ann):
"""If ann is Union[..., NoneType] return the non‑None part, else ann."""
if get_origin(ann) is Union and NoneType in get_args(ann):
return next(a for a in get_args(ann) if a is not NoneType)
return ann
2. Add dependency assertions for optional parameters: When optional parameters have dependencies on each other, use assertions to validate the relationships.
# Ensure dependent parameters are provided together
assert custom_instruction_proposer is None or reflection_lm is not None
# Or ensure at least one required parameter is provided
assert custom_proposer is not None or reflection_lm is not None
3. Avoid mutable default arguments: Never use mutable objects as default parameter values, as they create shared state across function calls.
# Wrong - shared mutable state
history: list[Completions] = Field(default=[])
# Correct - each instance gets its own list
history: list[Completions] = Field(default_factory=list)
4. Use idiomatic null coalescing: Prefer concise Python patterns for handling None values.
# Prefer this concise pattern
self.interpreter = interpreter or PythonInterpreter()
# Over verbose None checks
self.interpreter = interpreter if interpreter is not None else PythonInterpreter()
5. Avoid unnecessary Optional annotations: Don’t use Optional for parameters that have default values, as the default already handles the None case.
These patterns prevent common null-related bugs and make code more robust and maintainable.
Make configuration parameters optional with sensible defaults instead of requiring mandatory values, and only enable optional features when explicitly configured through environment variables or user settings.
Many configuration issues arise from rigid parameter requirements that don’t accommodate different use cases. Parameters should be optional when they’re not always needed, allowing users flexibility while providing sensible defaults for common scenarios.
Key principles:
Optional[Type] = None for parameters that aren’t always requiredExample of flexible configuration:
def __init__(
self,
model: str,
temperature: Optional[float] = None, # Instead of fixed 0.0
max_tokens: Optional[int] = None, # Instead of fixed 1000
reflection_lm: Optional[LM] = None, # Optional when using custom proposer
):
# Set defaults based on model capabilities
if temperature is None:
self.temperature = 0.0 if not is_reasoning_model(model) else None
# Only use optional features when explicitly configured
if reflection_lm is not None:
with dspy.context(lm=reflection_lm):
# Use reflection LM
else:
# Proceed without reflection LM
This approach prevents configuration errors while maintaining backward compatibility and providing users the flexibility they need for different scenarios.
When designing interfaces that handle multiple providers or services, organize the API structure around provider-specific logic rather than mixing different provider handling in generic components. Use provider-based props structures and create dedicated components or methods for each provider type.
For props design, structure them by provider with clear typing:
// Instead of flat props mixing all providers
interface Props {
posthogHost?: string;
posthogToken?: string;
ga4MeasurementId?: string;
}
// Use provider-based structure
interface Props {
posthog?: { host: string; token: string } | false;
ga4?: { measurementId: string } | false;
}
For component design, separate provider-specific logic:
// Instead of mixing provider logic in generic component
const GenericChecker = ({ provider, model }) => {
if (provider === 'ollama') {
// ollama-specific logic
} else {
// generic logic
}
};
// Create dedicated components or methods
const OllamaChecker = ({ model }) => { /* ollama-specific logic */ };
const GenericChecker = ({ model }) => { /* generic logic */ };
This approach improves maintainability, reduces conflicts between different provider implementations, and makes the interface more predictable for consumers.
When using postMessage for inter-window communication, avoid sending raw event data or generic message types that could expose sensitive information. Instead, use specific, predefined message types and only send the minimum necessary data.
This prevents potential information leakage and reduces the attack surface for malicious code that might intercept or manipulate cross-window messages.
Example:
// Avoid: Sending raw event data
window.parent.postMessage({
type: "dyad-shortcut-triggered",
key: e.key.toLowerCase(),
eventModifiers: {
ctrl: e.ctrlKey,
shift: e.shiftKey
}
});
// Prefer: Specific message type with minimal data
window.parent.postMessage({
type: "dyad-select-component-shortcut"
});
Ensure API documentation provides comprehensive, accurate information including limitations, complete workflow examples, and proper cross-references. API documentation should clearly state what endpoints do, what they don’t support, their constraints, and how they fit into larger workflows.
Key requirements:
Example of complete API workflow documentation:
// Upload file first
POST /api/v1/files
// Then use file_path in flow
{
"tweaks": {
"File-qYD5w": {
"path": ["returned_file_path"]
}
}
}
This ensures developers have all necessary information to successfully integrate with the API without encountering unexpected limitations or missing steps in their implementation.
Ensure field names, method names, and identifiers are consistent across different contexts including cross-language SDKs, API specifications, and data structures. When multiple naming options exist, prioritize alignment with established patterns and accurate representation of the underlying functionality or data.
For cross-platform consistency, align naming conventions between different language implementations:
# Good: Aligns with TypeScript SDK naming
can_use_tool: ToolPermissionCallback | None = None
# Avoid: Inconsistent with other SDK implementations
tool_permission_callback: ToolPermissionCallback | None = None
For API alignment, ensure field names match the actual data structure or API specification:
# Good: Matches actual API field name
total_cost_usd=data["total_cost_usd"]
# Avoid: Mismatched field name
cost_usd=data["cost_usd"] # when API actually uses "total_cost_usd"
Proactively identify naming inconsistencies during code reviews and prioritize fixes that improve overall system coherence.
Documentation should add genuine value by explaining non-obvious behavior, complex approaches, or important context that isn’t immediately clear from the code itself. Remove redundant docstrings and comments that merely restate what the code obviously does, while ensuring that sophisticated algorithms, design decisions, or non-trivial implementations are properly documented.
For example, remove obvious documentation like:
class CortexEstimatingTokenizer(EstimatingTokenizer):
"""Token estimator for Cortex.""" # Redundant - class name is self-explanatory
But add explanatory documentation for complex approaches:
# This approach works by embedding each capability content separately and using
# vector similarity search, which is more efficient than retrieving ALL documents
# and sorting manually because it leverages the database's optimized vector operations
async def find_relevant_capabilities(self, query: str, available_capabilities: Sequence[Capability]):
Focus documentation efforts on clarifying the “why” and “how” of complex logic rather than describing the “what” that’s already evident from well-written code.
Replace assertions, unhandled exceptions, and error-suppression mechanisms with proper error handling that provides clear, actionable feedback to users. Instead of allowing applications to crash or silently hide issues, implement structured error handling that communicates what went wrong and suggests next steps.
For example, replace crash-prone assertions:
# Avoid - can crash ungracefully
assert await params.indexer.index(container)
# Prefer - graceful handling with clear messaging
try:
success = await params.indexer.index(container)
if not success:
raise RuntimeError("Failed to index container. Check your configuration and try again.")
except Exception as e:
logger.error(f"Indexing failed: {e}")
raise RuntimeError("Indexing operation failed. Please verify your setup and retry.") from e
Similarly, avoid broad error suppression (like blanket ignore_missing_imports) that can mask real issues. Handle specific error cases individually to maintain visibility into potential problems while still providing a good user experience.
Avoid initializing authentication mechanisms, credentials, or identity objects when they are not actually used in the code. This follows the security principle of least privilege and reduces potential attack surface by minimizing credential exposure.
In test files particularly, only set up authentication when the test actually makes API calls or requires authenticated operations. Unnecessary authentication setup can lead to credential leakage and violates security best practices.
Example of what to avoid:
// Bad: Creating identity when no API calls are made
let identity: Identity;
beforeAll(async () => {
identity = await idmux({
name: "robots-txt",
concurrency: 100,
credits: 1000000,
});
});
// Good: Remove unused authentication setup
// (no identity initialization needed if no API calls)
Always review whether authentication setup is actually necessary for the functionality being implemented or tested.
Ensure consistent patterns, formatting, and conventions throughout the codebase. Inconsistencies in code style create confusion, reduce readability, and make maintenance more difficult.
Key areas to maintain consistency:
Import Organization: Group imports consistently and separate them with blank lines:
# Standard library imports
import os
from pathlib import Path
# Third-party imports
from lagom import Container
from pytest import fixture
# Internal imports
from emcie.server.core.common import ItemNotFoundError, JSONSerializable
Parameter Formatting: Use trailing commas consistently for multi-line parameters:
def create_session(
self,
end_user_id: EndUserId,
client_id: str,
) -> Session: # trailing comma enables easy additions
Naming and Capitalization: Choose one scheme and apply it consistently across similar contexts:
# Consistent predicate capitalization
"The user asks about weather" # or
"the user asks about weather" # but not mixed
Code Patterns: When establishing a pattern (like error handling, logging format, or method signatures), apply it uniformly across the codebase. Before introducing variations, consider if the existing pattern should be updated everywhere or if the new context truly requires different handling.
Review your changes to ensure they follow the same conventions used elsewhere in the codebase. When in doubt, search for similar code patterns and match their style.
Extract utilities, types, constants, and shared logic into dedicated modules to improve code maintainability and reduce duplication. When you find yourself writing similar code in multiple places, or when you have magic strings/numbers, inline type definitions, or mixed business logic, extract them into appropriate shared locations.
Examples of what to extract:
withTimeout, getDetailsToken to utils modulesconfig.$type<{...}> to separate type files'Origin File Not Found' and magic numbers with named constants// Before: Magic string and inline logic
throw new TRPCError({ code: 'BAD_REQUEST', message: 'Origin File Not Found' });
// After: Extract constant
const ERROR_MESSAGES = {
ORIGIN_FILE_NOT_FOUND: 'Origin File Not Found'
} as const;
throw new TRPCError({ code: 'BAD_REQUEST', message: ERROR_MESSAGES.ORIGIN_FILE_NOT_FOUND });
This practice reduces maintenance burden, prevents inconsistencies, and makes code more testable and reusable.
Choose appropriate data types for database columns to improve storage efficiency and performance. Use auto-incrementing identity columns for primary keys when there are no specific semantic requirements, and select column types with proper constraints based on expected data characteristics.
For primary keys without semantic meaning, prefer identity columns over text-based custom IDs:
// Preferred: Auto-incrementing identity
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
// Avoid: Custom text-based IDs when not semantically required
id: text('id').$defaultFn(() => idGenerator('usageRecords', 16)).primaryKey(),
For string columns, use varchar with appropriate length constraints instead of unbounded text types:
// Preferred: Constrained varchar for better storage
callType: varchar('call_type', { length: 256 }).notNull(),
// Avoid: Text with enum configuration when varchar suffices
callType: text('call_type', { enum: ['chat', 'history_summary'] }).notNull(),
This approach reduces storage overhead, improves query performance, and provides better data validation at the database level.
E2E tests should use stable, reliable selectors and waiting strategies to prevent flaky test failures. Prefer test IDs over CSS class names for element selection, as class names may change during refactoring and break tests. Use condition-based waits instead of arbitrary timeouts to ensure tests wait for the actual state changes rather than fixed time periods.
Example of robust selector usage:
// Avoid: brittle CSS class selector
const chatListItems = await po.page.locator(".chat-list-item");
// Prefer: stable test ID selector
const chatListItems = await po.page.getByTestId("chat-list-item");
// Avoid: arbitrary timeout
await po.page.waitForTimeout(500);
// Prefer: condition-based wait
await po.page.waitForSelector('[data-testid="search-results"]');
This approach makes tests more maintainable and reduces false failures caused by timing issues or UI refactoring.
Ensure that all configuration documentation accurately reflects the actual implementation, especially for build tools, tech stack, and architectural decisions. When documenting configurations that deviate from standard practices, provide clear rationale for the choices made.
Key areas to verify:
Example from the codebase:
# Incorrect documentation
- **Build Tools**: Turbo, Vite
# Corrected documentation
- **Build Tools**: Turbo (monorepo), Turbopack (Next.js dev), Webpack (Next.js prod)
- **Testing**: Vitest (uses Vite internally, but Vite not used directly in main build)
For architectural decisions like using multiple stores instead of the recommended single store pattern, document the complexity-based rationale and provide guidance on when each approach should be used. This prevents confusion during development and helps new team members understand the reasoning behind configuration choices.
Keep related documentation content together on a single page rather than fragmenting it across multiple pages. When users need to understand a complete concept or workflow, they should be able to find all relevant information in one location without having to navigate between multiple pages.
Avoid creating separate pages for closely related concepts that are better understood together. Instead of splitting content and creating circular cross-references, consolidate the information and use a single authoritative source.
For example, instead of having component parameters on one page and detailed usage instructions on another page that links back to the first, put both the parameters and usage instructions on the same page. Use clear section headings to organize the content within the page.
When you do need to reference information from another page, ensure there’s genuine value in the separation. Avoid links that simply point back to pages that already link to the current page, creating circular references with no additional context.
If a page becomes too long due to consolidation, consider whether the content represents multiple distinct concepts that genuinely warrant separate pages, or if better organization within a single page (using sections, tabs, or collapsible content) would serve users better.
When evaluating user-provided code or handling dynamic content, implement strict security measures to prevent malicious code execution and unauthorized access. This includes whitelisting allowed modules/imports, validating input integrity, and properly handling sensitive data.
Key practices:
Example of secure code evaluation:
# Whitelist allowed modules before evaluation
ALLOWED_MODULES = {'math', 'datetime', 'json'}
def eval_custom_component_code(code: str):
# Validate imports against whitelist
if not validate_imports(code, ALLOWED_MODULES):
raise SecurityError("Unauthorized module import detected")
# Generate secure hash to prevent spoofing
code_hash = hashlib.sha256(code.encode("utf-8")).hexdigest()
# Evaluate in restricted environment
return safe_eval(code, restricted_globals)
# Clear credentials after setup
finally:
# Scrub credentials from in-memory settings after setup
# Prevents users from gaining access to admin credentials by accessing environment variables
settings_service.auth_settings.reset_credentials()
This prevents attackers from injecting malicious code, accessing unauthorized modules, or exploiting credential exposure vulnerabilities.
When implementing conditional logic in CI workflows, ensure boolean expressions are precise and comprehensive to avoid unintended workflow execution or bypassing. Use multiple filter conditions combined with logical operators to create accurate triggers based on file changes.
For example, when creating a docs-only bypass condition, verify that documentation files changed AND no code files changed:
docs-only: ${{ steps.filter.outputs.docs == 'true' && steps.filter.outputs.python != 'true' && steps.filter.outputs.frontend != 'true' }}
Then use this condition in workflow steps:
elif [[ "${{ needs.check-nightly-status.outputs.should-proceed }}" != "true" && "${{ github.event_name }}" != "workflow_dispatch" && "$DOCS_ONLY" != "true" ]]; then
This prevents workflows from running unnecessarily on documentation-only changes while ensuring they still execute for any code modifications. Always test conditional logic thoroughly to ensure workflows behave as expected across different change scenarios.
Design configuration parameters to be language-agnostic when possible, use established configuration objects, and maintain consistency across language server implementations. Avoid language-specific CLI options or constructor parameters when the functionality could apply broadly.
Key principles:
--ls-max-memory instead of --max-memory for Intelephense-specific featuresLanguageServerConfig instead of adding new constructor parametersExample of good configuration design:
# Good: Use enum value for LS-specific settings
custom_settings = self._solidlsp_settings.ls_specifics.get("intelephense", {})
# Good: Generic CLI option that could apply to multiple language servers
@click.option("--ls-max-memory", type=int, help="Maximum memory (MB) for language server")
# Good: Use existing config object
def __init__(self, config: LanguageServerConfig, logger: LanguageServerLogger, ...):
max_memory = config.max_memory # Instead of separate parameter
# Good: Force user decision on new config
if "ignore_all_files_in_gitignore" not in config_dict:
raise ValueError("Missing required config: ignore_all_files_in_gitignore")
This approach ensures configuration remains maintainable, user-friendly, and consistent as the codebase grows across multiple language servers.
When configuring text processing components that work with AI embedding models, proactively consider tokenization limits and chunk size constraints. Many embedding models have practical token limits that are lower than their theoretical maximums, and text splitting components may not enforce exact chunk sizes.
Always test your chunk size configuration with your specific embedding model to avoid tokenization errors. If you encounter issues, reduce chunk sizes (try 500 tokens or less), adjust overlap settings, or modify separator strategies.
Example configuration considerations:
# Split Text component
chunk_size: 500 # Conservative size for embedding models
chunk_overlap: 50 # Reasonable overlap
separator: "\n\n" # Common separator for consistent splits
# Test with your embedding model
# Inspect component output to verify actual chunk sizes
Document any model-specific limitations in your component descriptions and provide fallback strategies. This is especially important for NVIDIA embedding models like nvidia/nv-embed-v1 and other specialized AI models that may have stricter practical limits than advertised.
When integrating with different LLM providers, create proper base class abstractions that filter and validate parameters based on each provider’s capabilities. Follow established architectural patterns rather than creating custom configuration approaches.
Create provider-specific base classes that define supported parameters and filter hints accordingly. This prevents passing unsupported parameters to APIs and maintains consistency across adapters.
Example implementation:
class OpenAIBaseSchematicGenerator(BaseSchematicGenerator[T], ABC):
supported_arguments = ["temperature", "logit_bias", "max_tokens"]
async def generate(self, prompt: str, hints: Optional[dict[str, Any]] = None):
filtered_hints = {}
if hints:
for k, v in hints.items():
if k not in self.supported_arguments:
self.logger.warning(f"Key '{k}' is not supported. Skipping...")
continue
filtered_hints[k] = v
response = await self._client.chat.completions.create(
model=self._get_model_name(),
**filtered_hints
)
This approach allows code to specify provider requirements (“I want an OpenAI model”) while ensuring only valid parameters are passed to each API. Use existing patterns like CustomSchematicGenerator and FallbackSchematicGenerator rather than implementing custom configuration systems that diverge from established adapter architectures.
Always use defensive programming patterns in migration scripts to ensure they can be executed multiple times without errors. This prevents failures during re-execution scenarios and makes migrations more robust.
Key patterns to implement:
CREATE TABLE IF NOT EXISTS instead of CREATE TABLEALTER TABLE ADD COLUMN IF NOT EXISTS instead of ALTER TABLE ADD COLUMNExample:
-- Good: Idempotent migration
CREATE TABLE IF NOT EXISTS "chat_groups" (
"id" text PRIMARY KEY NOT NULL,
"title" text
);
ALTER TABLE "messages" ADD COLUMN IF NOT EXISTS "group_id" text;
-- Bad: Non-idempotent migration
CREATE TABLE "chat_groups" (
"id" text PRIMARY KEY NOT NULL,
"title" text
);
ALTER TABLE "messages" ADD COLUMN "group_id" text;
This approach ensures migrations won’t fail with “already exists” errors when run multiple times, which is common during development, testing, and deployment scenarios.
Always use os.environ.get() with appropriate defaults instead of direct dictionary access to prevent KeyError exceptions when environment variables are not set. Additionally, extract configuration constants and magic numbers to named module-level variables for better maintainability and consistency.
This pattern prevents runtime crashes when optional environment variables are missing and makes configuration values more discoverable and maintainable.
Problematic pattern:
api_version = os.environ["AZURE_API_VERSION"] or "2024-08-01-preview" # KeyError if not set
await asyncio.sleep(10) # Magic number
Preferred pattern:
# Module-level constants
DEFAULT_API_VERSION = "2024-08-01-preview"
EXTENDED_PERIOD_OF_TIME = 10
# Safe environment variable access
api_version = os.environ.get("AZURE_API_VERSION", DEFAULT_API_VERSION)
await asyncio.sleep(EXTENDED_PERIOD_OF_TIME)
This approach ensures graceful handling of missing environment variables while making configuration values explicit and easily adjustable across the codebase.
Avoid complex, multi-layered error handling that obscures error origins and makes debugging difficult. Each error should be handled at the most appropriate level without unnecessary re-parsing or nested try-catch blocks.
Problems with complex error flows:
Instead, handle errors close to their source and use clear, single-responsibility error handling:
// ❌ Avoid: Complex nested error handling
async parseFile(fileId: string): Promise<LobeDocument> {
try {
const { filePath, file, cleanup } = await this.fileService.downloadFileToLocal(fileId);
try {
const fileDocument = await loadFile(filePath);
// ... processing
} catch (error) {
console.error(`File parsing failed:`, error);
throw error;
} finally {
cleanup();
}
} catch (error) {
console.error(`File not found:`, error);
throw error;
}
}
// ✅ Better: Single-level error handling with clear responsibility
async parseFile(fileId: string): Promise<LobeDocument> {
const { filePath, file, cleanup } = await this.fileService.downloadFileToLocal(fileId);
try {
const fileDocument = await loadFile(filePath);
// ... processing
return document;
} catch (error) {
console.error(`[${file.name}] File parsing failed:`, error);
throw error;
} finally {
cleanup();
}
}
Keep error handling flows simple and direct to improve code maintainability and debugging experience.
Configuration values such as URLs, endpoints, timeouts, and environment-specific settings should never be hardcoded in source code. Instead, they should be read from configuration files, environment variables, or other configurable sources to ensure flexibility across different environments and deployments.
Hardcoded values make applications inflexible and difficult to deploy across different environments. They also make it impossible for users to customize behavior according to their specific needs.
Example of what to avoid:
// Bad: hardcoded URL
const response = await fetch("http://localhost:11434/api/tags")
// Good: configurable URL
const baseUrl = config.ollama?.baseUrl || "http://localhost:11434"
const response = await fetch(`${baseUrl}/api/tags`)
When implementing configuration options, ensure they behave consistently across all applicable contexts. For instance, if a timeout setting is provided, it should apply regardless of the provider type, unless there are specific technical constraints that prevent this.
Maintain consistent AI model metadata and configuration across all providers to prevent breaking changes and ensure reliable behavior. When adding new models or updating existing ones, always update corresponding token limits, default configurations, and provider mappings simultaneously.
Key practices:
models.rs) rather than scattered across provider filesmodel.fast_model = Some(ANTHROPIC_DEFAULT_FAST_MODEL)Example from the discussions:
// Good: Centralized model limits
static MODEL_SPECIFIC_LIMITS: Lazy<Vec<(&'static str, usize)>> = Lazy::new(|| {
vec![
("gpt-4o", 128_000),
("claude-3-5-sonnet", 200_000),
("moonshotai/kimi-k2-instruct", 131_072), // Added with corresponding limit
]
});
// Good: Using constants for defaults
const ANTHROPIC_DEFAULT_FAST_MODEL: &str = "claude-3-5-haiku-latest";
model = model.with_fast(ANTHROPIC_DEFAULT_FAST_MODEL);
This prevents user disruption from inconsistent model behavior and ensures that model updates don’t break existing workflows or introduce undefined behavior due to missing configuration.
Ensure comprehensive and accurate documentation of environment variables, including cross-references, auto-detection behavior, and deployment context. When documenting configuration options, always provide links to the environment variables page and specify the exact variable name. Include information about auto-detected variables that Langflow recognizes by default, and provide deployment-specific context such as Docker usage.
For example, when documenting file upload configuration:
Increased the default maximum size for file uploads from 100 MB to 1024 MB.
You can configure this with the [`LANGFLOW_MAX_FILE_SIZE_UPLOAD`](/environment-variables#LANGFLOW_MAX_FILE_SIZE_UPLOAD) environment variable.
When running a Langflow Docker image, the `-e` flag sets system environment variables:
```bash
docker run -e LANGFLOW_MAX_FILE_SIZE_UPLOAD=2048 langflow
Additionally, document the precise behavior and interactions between related environment variables. For complex variables like authentication settings, clearly explain conditional behavior:
If set to `true`, and `LANGFLOW_AUTO_LOGIN` is set to `true`, skips authentication and allows automatic login as the superuser. If `LANGFLOW_AUTO_LOGIN` is `false`, has no effect.
This ensures users understand not just what variables exist, but how to use them effectively across different deployment scenarios and how they interact with other configuration options.
When implementing security controls, always default to the most restrictive option and require explicit opt-in for more permissive behavior. This applies to authentication mechanisms, user permissions, and security scanning workflows.
For authentication, use centralized middleware instead of manual verification in each handler:
// Instead of manual verification in each handler
async fn start_agent(
State(state): State<Arc<AppState>>,
headers: HeaderMap,
Json(payload): Json<StartAgentRequest>,
) -> Result<Json<StartAgentResponse>, (StatusCode, Json<ErrorResponse>)> {
verify_secret_key(&headers, &state).map_err(|_| {
// ... error handling
})?;
// ... handler logic
}
// Use middleware for consistent auth across all protected routes
For permission systems, implement security checks before user interaction and default to the most restrictive option available. When multiple security mechanisms exist (like permission checking and security scanning), apply the least permissive result from all checks.
This principle ensures that security is the default state, reducing the risk of accidentally exposing functionality or data through overly permissive configurations.
Identify and eliminate duplicated code by extracting shared functionality to appropriate locations. When multiple components or code sections perform identical operations, consolidate the logic into a single, reusable location such as a parent component, utility function, or shared module.
Key strategies:
Example of eliminating platform duplication:
// Before: Duplicated code for different platforms
if (detectedPlatform === "powershell") {
const authHeader = ` -H "x-api-key: YOUR_API_KEY_HERE"`;
uploadCommands.push(`curl -X POST "${baseUrl}/api/v1/files/upload/${flowId}"${authHeader} -F "file=@your_image.jpg"`);
} else {
const authHeader = ` -H "x-api-key: YOUR_API_KEY_HERE"`;
uploadCommands.push(`curl -X POST "${baseUrl}/api/v1/files/upload/${flowId}"${authHeader} -F "file=@your_image.jpg"`);
}
// After: Extracted shared logic
const authHeader = ` -H "x-api-key: YOUR_API_KEY_HERE"`;
uploadCommands.push(`curl -X POST "${baseUrl}/api/v1/files/upload/${flowId}"${authHeader} -F "file=@your_image.jpg"`);
This approach improves maintainability, reduces the likelihood of inconsistencies, and makes the codebase more readable by eliminating redundant patterns.
Always identify and properly protect sensitive data fields in your code. Sensitive information includes IP addresses, API keys, authentication tokens, personal identification data, and high-privilege credentials.
Key practices:
Example of proper sensitive data handling:
// Bad: Storing IP address unnecessarily
export const usageRecords = pgTable('usage_records', {
ipAddress: text('ip_address'), // Remove this sensitive field
});
// Good: Encrypt sensitive user data
const encryptedKeyVaults = encrypt(userKeyVaults); // Encrypt API keys before storage
// Good: Be cautious with webhook data containing sensitive fields
const parsed = JSON.parse(payloadString) as CasdoorWebhookPayload;
// Be aware this may contain accessKey, accessSecret, idCard, etc.
Always ask: “Does this field contain sensitive information?” and “How can I minimize exposure while maintaining functionality?”
Use containerization to isolate operations that could access sensitive data, modify critical systems, or execute untrusted code. Containers provide a secure boundary that prevents workflows from affecting the host environment or accessing resources beyond their intended scope.
This practice is essential when:
Example implementation:
# GitHub Actions workflow
- name: Scan recipes in isolation
run: |
docker run --rm \
--network none \
--read-only \
-v $(pwd)/recipes:/recipes:ro \
recipe-scanner:latest \
scan /recipes
# Development workflow
container-use stdio
# Run a container agent to add a feature to save my to-do list data in sqlite,
# build and run tests, but use a separate Git branch so my main code stays safe.
Always prefer containerized execution over direct host execution when dealing with potentially unsafe operations, ensuring that failures or security issues remain contained within the isolated environment.
Understand React’s built-in optimizations and avoid unnecessary dependencies in hook arrays. React guarantees that state setters maintain referential stability across re-renders, so they don’t need to be included in dependency arrays. Similarly, ref objects themselves don’t change - only their .current property does, and changes to .current don’t trigger re-renders, so refs don’t need to be in dependency arrays either.
Use useCallback when functions are passed to dependency arrays of other hooks, but avoid premature optimization. As one developer noted: “We could have gotten away with keeping this a function re-created on every render… but we’d have to suppress some warnings and potentially invite some future bugs. Using hooks for all of them seemed the right way to go.”
Example of proper dependency management:
const performSubmit = useCallback(
(text?: string) => {
// Function logic here
},
[
allDroppedFiles,
displayValue,
handleSubmit,
// Don't include: setters, refs, or other stable values
]
);
useEffect(() => {
if (recipeAccepted && initialPrompt && messages.length === 0) {
setDisplayValue(initialPrompt); // setter doesn't need to be in deps
hasSetRecipePromptRef.current = true; // ref doesn't need to be in deps
}
}, [recipeAccepted, initialPrompt, messages.length]); // Only include values that actually change
Establish consistent patterns for handling headers in API clients to avoid duplication and ensure predictable behavior. When designing API client interfaces, clearly define header precedence rules and avoid setting headers in multiple locations unless absolutely necessary.
Key principles:
Header Precedence: Decide whether persistent headers should override request-specific headers or vice versa. Document this decision clearly. As one developer noted: “if the provider made the effort to set a persistent header, that it shouldn’t be overridden.”
Avoid Duplication: Don’t set the same headers in multiple places unless there’s a technical requirement. If duplication is necessary, document why both locations are needed.
Clean Construction: Use efficient header object construction patterns instead of multiple mutations.
Example of clean header construction:
// Preferred: Clean, efficient construction
const headers = {
'anthropic-beta': betas.length > 0 ? betas.join(",") : undefined,
'idempotency-key': taskId && checkpointNumber !== undefined ? this.getIdempotencyKey(taskId, checkpointNumber) : undefined,
}
// Avoid: Multiple object mutations
const headers: Record<string, string> = {}
if (betas.length > 0) {
headers["anthropic-beta"] = betas.join(",")
}
if (taskId && checkpointNumber !== undefined) {
headers["idempotency-key"] = this.getIdempotencyKey(taskId, checkpointNumber)
}
This ensures API clients are maintainable, predictable, and efficient in their header management.
Develop CI/CD workflows incrementally, starting with simpler versions and adding complexity gradually. This approach makes testing easier and reduces the risk of introducing breaking changes. When adding new steps or jobs, consider their performance impact and dependencies on other workflow components.
Start by implementing basic functionality first, then progressively add advanced features like release automation or complex build matrices. For example, when creating a new build workflow, begin with a single architecture or platform, test thoroughly, then expand to multiple targets.
When adding new CI steps, evaluate whether they should run in parallel jobs or be integrated into existing ones based on dependencies and performance considerations. Monitor build times and be prepared to refactor job organization if performance degrades.
Example approach:
# Phase 1: Basic build only
- name: build
run: cargo build --release
# Phase 2: Add testing after basic build is stable
- name: test
run: cargo test
# Phase 3: Add release automation once build/test is proven
- name: release
if: github.ref == 'refs/heads/main'
run: ./scripts/release.sh
This incremental strategy helps identify issues early and makes workflow changes easier to debug and maintain.
Avoid using print statements (println!, eprintln!) or custom logging implementations for application logging. Instead, use established logging libraries like tracing that provide proper log levels, structured output, and configurable destinations.
Print statements bypass logging configuration and cannot be controlled at runtime. Custom logging implementations are error-prone and lack the features of mature libraries. Established logging libraries offer better performance, structured data support, and integration with monitoring systems.
Replace debug prints with appropriate log levels:
// Instead of this:
println!("🔒 SecurityManager::new() called - checking if security should be enabled");
// Use this:
tracing::debug!("SecurityManager::new() called - checking if security should be enabled");
For custom logging needs, extend existing logging infrastructure rather than creating new implementations:
// Instead of rolling your own:
pub fn log_debug_event(event: &str) {
// custom file writing logic...
}
// Use tracing with appropriate configuration:
tracing::debug!(event = %event, "debug event occurred");
This ensures consistent logging behavior, proper log level control, and integration with the application’s logging configuration.
For security-critical applications, prefer inlining external dependencies (JavaScript libraries, CSS frameworks) rather than loading them from CDNs or external sources at runtime. This approach eliminates risks from compromised external sources, network-based attacks, and supply chain vulnerabilities.
Inlining dependencies provides “zero risk” by ensuring complete control over the code being executed and removing external attack vectors. This is especially important for core functionality and recommended features that users rely on.
Example:
<!-- Preferred: Inline the minified library -->
<script>
{{CHART_MIN}}
// Minified D3.js or other library code here
</script>
<!-- Avoid: External CDN dependency -->
<script src="https://cdn.example.com/d3.min.js"></script>
Consider external dependencies acceptable for optional third-party extensions where users make explicit choices about trust, but default to inlined dependencies for built-in functionality.
Replace panic-inducing operations like .expect() and .unwrap() with proper error handling that allows graceful recovery or controlled failure. Panics can crash entire applications and provide poor user experience, especially in server environments where “it will kill goosed and it is all over.”
Instead of panicking, use Result types, .ok_or() methods, or provide sensible defaults:
// Instead of panicking:
let stderr = stderr.take().expect("should have a stderr handle");
// Use proper error handling:
let stderr = stderr.take().ok_or_else(||
ExtensionError::ConfigError("Missing stderr handle".to_string()))?;
// Or provide defaults when appropriate:
fn get_current_working_dir() -> PathBuf {
std::env::current_dir()
.unwrap_or_else(|_| get_home_dir())
}
When encountering unexpected None values or potential failures, log the issue and either return an appropriate error or continue with a reasonable fallback. This approach makes applications more resilient and provides better debugging information when issues occur.
Replace hardcoded configuration values with configurable parameters to improve flexibility and maintainability. Hardcoded timeouts, domain strings, validation constraints, and operational parameters should be exposed as advanced inputs, environment variables, or settings.
Examples of improvements:
timeout_seconds parameter instead of hardcoded timeout=600domain input instead of hardcoded "audio.transcription"http:// for local development while defaulting to https:// for productionMAX_SESSIONS_PER_SERVER, SESSION_IDLE_TIMEOUT that can be overridden via settings# Instead of hardcoded values:
response = client.predictions.wait(response.id, timeout=600)
domain = "audio.transcription"
# Use configurable parameters:
IntInput(
name="timeout_seconds",
display_name="Timeout (seconds)",
value=600,
advanced=True,
info="Maximum time to wait for processing completion"
)
DropdownInput(
name="domain",
display_name="Processing Domain",
options=["audio.transcription", "audio.diarization"],
value="audio.transcription",
advanced=True
)
This approach enables users to customize behavior for their specific use cases, supports different environments (development vs production), and makes the code more maintainable by centralizing configuration management.
Always use safe access patterns to prevent runtime errors when dealing with potentially null or undefined values. Instead of direct access that can raise KeyError or IndexError, use defensive programming techniques.
For dictionary access, prefer dict.get(key) or check key in dict before accessing:
# Bad - raises KeyError if key missing
if not os.environ["LITELLM_PROVIDER_MODEL_NAME"]:
# Good - safe access patterns
if "LITELLM_PROVIDER_MODEL_NAME" not in os.environ:
# or
if not os.environ.get("LITELLM_PROVIDER_MODEL_NAME"):
For collections, validate bounds before indexing:
# Bad - IndexError if empty
generation = event_generation_result.generations[0]
# Good - check bounds first
if not event_generation_result.generations:
raise ValueError("No generations available")
generation = event_generation_result.generations[0]
Use null coalescing for function parameters:
# Ensure non-null defaults
arguments = tc.arguments or {}
hints = hints or {} # instead of Optional[dict] = None
This prevents common runtime exceptions and makes code more robust when handling optional or potentially missing data.
When you’re certain a value will be initialized but TypeScript can’t infer this, use the definite assignment assertion operator (!) instead of as any or suppressing type errors. This maintains type safety while avoiding unnecessary null checks throughout your codebase.
Avoid this pattern:
// Creates unnecessary undefined checks everywhere
#agent: Agent<Env, State> | undefined;
// Or suppressing valid type concerns
// @ts-expect-error TODO: fix this type error
await this._drainStream(response.body);
// Or forcing types unsafely
}) as any
Instead, use definite assignment assertions when you know the value will be there:
// Tells TypeScript "trust us, it'll always be there"
#agent: Agent<Env, State>!;
Or add proper null checks when the value might actually be null:
// When the value could legitimately be null/undefined
if (response.body) {
const reader = response.body.getReader();
// ... handle the stream
}
This approach maintains TypeScript’s null safety benefits while eliminating false positives that lead to code pollution or unsafe type assertions.
Identify code paths that execute frequently and ensure they use performant, non-blocking solutions. Frequent operations should avoid expensive database queries, CPU-intensive synchronous processing, or anything that can block the event loop.
For high-frequency database operations, use caching solutions like Redis instead of direct database queries. For CPU-intensive tasks like HTML parsing that run often, consider moving the logic to more performant runtimes or libraries.
Example of what to avoid:
// Bad: DB query on every job insert
const { data: recentNotifications } = await supabase_service
.from("user_notifications")
.select("*")
.eq("team_id", team_id)
.gte("sent_date", pastDate.toISOString());
Example of better approach:
// Good: Use Redis for frequent lookups
const recentNotifications = await redis.get(`notifications:${team_id}`);
Before implementing any operation that will run frequently, evaluate its performance impact and consider alternatives like caching, background processing, or more efficient libraries/runtimes.
Always validate and sanitize inputs to IPC handlers to prevent unauthorized access to system resources. Implement allowlists or blocklists for file system operations and maintain secure Electron configuration.
IPC handlers that accept file paths, URLs, or other system resources can be exploited if not properly validated. Even with secure Electron configuration (context isolation enabled, node integration disabled), IPC endpoints remain potential attack vectors.
Example of vulnerable code:
ipcMain.handle('open-directory-in-explorer', async (_event, path: string) => {
// Dangerous: path can be any directory on the machine
shell.openPath(path);
});
Secure implementation:
const ALLOWED_DIRECTORIES = ['/safe/app/directory', '/user/documents'];
ipcMain.handle('open-directory-in-explorer', async (_event, path: string) => {
// Validate path is in allowlist
const normalizedPath = path.normalize(path);
if (!ALLOWED_DIRECTORIES.some(allowed => normalizedPath.startsWith(allowed))) {
throw new Error('Directory access not permitted');
}
shell.openPath(normalizedPath);
});
Ensure your Electron app maintains secure configuration: context isolation enabled, node integration disabled, web security enabled, and controlled API surface through preload scripts with explicit method exposure.
Avoid accessing internal object attributes like __dict__ or using unpacking syntax when cleaner alternatives exist. Instead, prefer stable public methods or direct assignment patterns that don’t couple to object internals.
For object attribute access, use stable methods when available:
# Avoid
"usage": response.usage.__dict__ if hasattr(response, "usage") else None
# Prefer
"usage": response.usage.model_dump() if hasattr(response, "usage") else None
# or explicitly map known fields
"usage": {"tokens": response.usage.tokens, "cost": response.usage.cost} if hasattr(response, "usage") else None
For list/tuple assignments, use direct assignment when possible:
# Avoid
outputs = [*BaseFileComponent._base_outputs]
# Prefer
outputs = BaseFileComponent._base_outputs
This approach reduces coupling to implementation details, improves maintainability, and makes code more resilient to internal API changes.
Ensure all database operations and access to database objects occur within the appropriate session scope. Database objects become invalid once their session is closed, leading to runtime errors when accessed later.
Always perform database queries and access object attributes within the same session context. If you need to use database object attributes after the session, extract the needed values while the session is still active.
Example of the problem:
async def update_build_config(self, build_config, field_value, field_name=None):
if field_name == "knowledge_base":
async with session_scope() as db:
current_user = await get_user_by_id(db, self.user_id)
# BAD: Accessing current_user.username after session is closed
kb_user = current_user.username
Correct approach:
async def update_build_config(self, build_config, field_value, field_name=None):
if field_name == "knowledge_base":
async with session_scope() as db:
current_user = await get_user_by_id(db, self.user_id)
# GOOD: Access attributes within session scope
kb_user = current_user.username
Additionally, consider the timing of database availability checks. Operations that verify database state (like table existence) should occur after initialization is complete, not during the initial setup phase.
Always sanitize trace metadata and attributes before sending to observability platforms to ensure compatibility with OpenTelemetry attribute type restrictions. Complex objects, custom types, and non-primitive values should be converted to supported types (str, int, float, bool, None) or JSON strings to prevent warnings and ensure reliable trace data.
Implement sanitization methods that:
Example implementation:
def sanitize_for_otel(value):
"""Sanitize values for OpenTelemetry attribute compatibility."""
if value is None or isinstance(value, (str, int, float, bool)):
return value
elif isinstance(value, (list, tuple)):
return [sanitize_for_otel(item) for item in value]
elif isinstance(value, dict):
try:
return json.dumps(value)
except (TypeError, ValueError):
return str(value)
else:
return str(value)
# Usage in trace metadata
span.set_attributes({
key: sanitize_for_otel(value)
for key, value in metadata.items()
})
This prevents OpenTelemetry warnings like “Invalid type StructuredTool in attribute” and ensures consistent trace data across different observability platforms (Traceloop, Opik, Arize Phoenix).
Ensure thorough validation of API inputs and outputs using robust validation techniques rather than simple string checks or partial validation. Use proper libraries for validation (like urllib.parse for URLs) and validate all required components, not just a subset.
For URL validation, avoid simple string prefix checks:
# Avoid this
if source_name.startswith("http"):
# process URL
# Use this instead
from urllib.parse import urlparse
parsed = urlparse(source_name)
if parsed.scheme in ['http', 'https', 's3', 'gs']:
# process URL
For component validation, ensure completeness:
# Avoid partial validation
if "Chat Input" not in display_names:
raise ValueError("Missing ChatInput component")
# Validate all required components
required_components = ["Chat Input", "Chat Output"]
missing = [comp for comp in required_components if comp not in display_names]
if missing:
raise ValueError(f"Missing required components: {missing}")
This prevents runtime errors, improves API reliability, and ensures consistent behavior across different input scenarios.
Actively identify and eliminate code duplication by extracting repeated logic into reusable functions, using loops instead of repetitive code blocks, and consolidating similar implementations. When you find yourself copying and pasting code or writing nearly identical logic multiple times, refactor it into a shared function or use iteration patterns.
For example, instead of repeating similar command creation logic:
// Before: Duplicated command creation
let output = if cfg!(target_os = "windows") {
Command::new("cmd")
.args(["/C", command])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.kill_on_drop(true)
.output()
.await?
} else {
Command::new("sh")
.args(["-c", command])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.kill_on_drop(true)
.output()
.await?
};
// After: Consolidated approach
let mut command = if cfg!(target_os = "windows") {
Command::new("cmd").args(["/C", command])
} else {
Command::new("sh").args(["-c", command])
};
let output = command
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null())
.kill_on_drop(true)
.output()
.await?;
Similarly, replace repetitive field processing with loops, extract common validation logic into helper functions, and consolidate similar error handling patterns. This improves maintainability, reduces the chance of bugs from inconsistent implementations, and makes the codebase more readable and easier to modify.
Prefer consolidating common configuration and parameters in API constructors or base methods rather than requiring multiple method calls, complex parameter passing, or external configuration loading. This reduces API surface area and makes interfaces easier to use for consumers.
When designing APIs, favor approaches that:
Example of preferred approach:
// Instead of separate methods for each model type
pub async fn complete_with_model(&self, model: Option<String>) -> Result<Message> {
let model = model.unwrap_or_else(|| self.default_model());
// implementation
}
// Instead of requiring multiple setup calls
pub fn new(api_key: String) -> Result<Self> {
let mut client = ApiClient::new(host, auth)?;
// Load common config automatically
if let Some(tls_config) = TlsConfig::from_config()? {
client = client.with_tls_config(tls_config)?;
}
Ok(Self { client })
}
// Instead of string-based parameters, use direct types
pub fn create_tool(schema: serde_json::Value) -> Tool {
// Use schema directly instead of requiring JSON string
}
This approach reduces the cognitive load on API consumers and prevents the need to understand complex setup sequences or parameter serialization formats.
When operations cannot complete successfully or return meaningful results, explicitly return None rather than raising exceptions or using placeholder values. Document when None is expected and ensure consistent None handling throughout the codebase.
Prefer explicit None returns when:
Always document when None is possible and what it represents:
def get_relative_path(self) -> str | None:
"""
Get the relative path of the file containing the symbol.
:return: the relative path, or None if the symbol is defined
outside of the project's scope
"""
return self.symbol.location.relative_path
# Better than using defaults or exceptions
def find_executable() -> str | None:
"""Find the executable path, or None if not found."""
path = shutil.which("executable")
return path # Returns None if not found, caller handles it
# Consistent None handling throughout
if relative_path is None:
# Handle the None case appropriately
continue # or return, or use fallback logic
This approach makes error conditions explicit, prevents silent failures, and allows callers to make informed decisions about how to handle missing or invalid data.
Ensure all API interfaces have clearly documented contracts specifying expected request/response formats, data encoding standards, and return types. This prevents integration issues and enables reliable external consumption.
When designing callback functions or data exchange formats, explicitly document:
Example from callback responses:
const handleUIAction = useCallback(async (result: UIActionResult) => {
// Process the action...
// IMPORTANT: Always return documented response format
const response = {
type: 'ui-message-response',
payload: result,
};
return response;
}, []);
Consider adding TypeScript interfaces or runtime validation to enforce documented contracts. For data formats like deeplinks, establish official standards (e.g., “use URL_SAFE_NO_PAD base64”) and implement backwards-compatible decoding to handle legacy formats during transitions.
Ensure that sensitive authentication data such as API keys, tokens, passwords, and other credentials are never exposed in documentation, client-side code, logs, or configuration files. This includes both preventing accidental inclusion in documentation and implementing proper secure handling in application code.
Key practices:
Example from authentication form:
// Good: Using FormPassword for sensitive data
<FormPassword
autoComplete="new-password"
placeholder={t('comfyui.apiKey.placeholder')}
/>
// Good: Using FormPassword for passwords
<FormPassword
autoComplete="new-password"
placeholder={t('comfyui.password.placeholder')}
/>
This practice prevents credential theft, unauthorized access, and security breaches that can occur when sensitive authentication data is inadvertently exposed through various channels.
Make deliberate, context-appropriate decisions about error handling strategy rather than applying generic patterns. Consider whether each error scenario should fail fast, provide graceful degradation, or offer recovery options based on the specific business impact and user experience requirements.
Key principles:
Example of intentional error handling:
# Fail fast for critical dependencies
try:
from required_library import CriticalClass
except ImportError as e:
msg = "Required library not installed. Install with: pip install required_library"
raise ImportError(msg) from e
# Graceful degradation for optional features
try:
dependency_info = analyze_component_dependencies(code)
metadata["dependencies"] = dependency_info
except (SyntaxError, TypeError, ValueError) as exc:
logger.warning(f"Failed to analyze dependencies for {name}: {exc}")
# Continue without dependency info - this is optional
The choice between failing fast and graceful degradation should be explicit and documented, considering the impact on users and the ability to debug issues effectively.
Use environment variables to control application behavior and ensure configuration changes are properly synchronized between in-memory state and persistent storage. When configuration depends on environment context, check for relevant environment variables first before falling back to defaults.
This prevents inconsistencies where in-memory configuration differs from persisted configuration, and allows for environment-specific behavior without hardcoding values.
Example patterns:
// Check environment variable before generating defaults
const key = process.env.GOOSE_SERVER__SECRET_KEY ||
(process.env.GOOSE_EXTERNAL_BACKEND ? 'test' : crypto.randomBytes(32).toString('hex'));
// Enable development features via environment
if (process.env.ENABLE_DEV_UPDATES === 'true') {
autoUpdater.forceDevUpdateConfig = true;
}
When modifying configuration in memory, ensure changes are also reflected in the persistent storage layer to maintain consistency, or clearly document when temporary in-memory modifications are intentional.
Eliminate code duplication by extracting repeated values and components into well-organized constants. This applies at both the variable level (extracting duplicate literal values) and file level (separating reusable components).
For duplicate values, extract them to named constants:
// Instead of:
const [downloadUrls, setDownloadUrls] = useState({
deb: "https://github.com/block/goose/releases/latest",
rpm: "https://github.com/block/goose/releases/latest"
});
// Use:
const LATEST_RELEASE_URL = "https://github.com/block/goose/releases/latest";
const [downloadUrls, setDownloadUrls] = useState({
deb: LATEST_RELEASE_URL,
rpm: LATEST_RELEASE_URL
});
For reusable components, consider separating them into individual files rather than grouping them in a single constants file:
// Instead of: src/components/Constants.js (with multiple components)
// Use: src/components/DesktopProviderSetup.js
// src/components/ModelSelectionTip.js
This improves maintainability, reduces the risk of inconsistencies, and makes the codebase more modular and easier to navigate.
Documentation should prioritize user needs and problems over technical implementation details. Start with the “why” - what problem does this solve and when would users need it? Provide clear use cases and benefits before diving into technical specifics.
Structure documentation to guide users through their journey:
Move implementation details, technical architecture, and contributing guidelines to separate technical documentation when they don’t directly serve user goals.
Example structure:
# Feature Name
## What problem does this solve?
Help users understand when they need this feature...
## Use cases
- Run this when you want to...
- Use this for...
## Quick start
Simple example with expected output...
## Benefits
What you can accomplish after setup...
Avoid documentation that “reads more like internal technical documentation than a user guide” by consistently asking: “Does this help users accomplish their goals?”
Choose clear, descriptive names for variables, methods, types, and parameters that unambiguously convey their purpose and avoid conflicts. Prefer full words over abbreviations and ensure names are specific enough to prevent clashes with inherited or similar functionality.
Examples of improvements:
options instead of opts for better clarityTransportType instead of Protocol when the term “protocol” is overloaded in the domainonMcpError instead of onError to avoid conflicts with base class methodsThis practice reduces cognitive load, prevents naming conflicts during inheritance or composition, and makes code more maintainable by clearly expressing intent through naming.
When configuring client access to an external API, store the provider’s base endpoint as a fully-qualified URL that already includes the required API version (and defaults). Avoid splitting “base URL” and “version” in ways that can drift or be forgotten—make the endpoint unambiguous.
Example (.env.example style):
# Provider base endpoint including version path
OPENAI_ENDPOINT=https://api.openai.com/v1
# If using Azure, include the full endpoint and keep the version as part of the endpoint you call
# (or ensure the final request URL includes the version parameter/path consistently)
AZURE_OPENAI_ENDPOINT=https://<resource>.openai.azure.com/
AZURE_API_VERSION=2024-xx-xx
Application guidance:
*_ENDPOINT (include /v1 or the API-version component).https://api.openai.com/v1).Always add test coverage for new functionality, especially when introducing integrations or services. Use mocks and patches when testing external dependencies. Additionally, configure coverage reporting to exclude irrelevant paths like legacy components, deactivated features, and test files themselves to maintain meaningful coverage metrics.
Example coverage configuration:
# .coveragerc
[run]
source = src/backend/base/langflow
omit =
# Test files
*/tests/*
*/test_*
# Deactivated Components
*/components/deactivated/*
# Legacy components with legacy = True
*/components/legacy_component.py
When adding tests, use appropriate mocking:
# Example test with mocking
@patch('module.external_service')
def test_tracing_functionality(mock_service):
mock_service.return_value = expected_result
# Test implementation
assert result == expected_result
Maintain consistent naming for the same entities across different contexts including code, documentation, APIs, and external systems. When names must differ between contexts, implement fallback mechanisms to handle variations gracefully.
Key principles:
Example from codebase:
// Handle repository name variations gracefully
const tries = [
app.repo, // First try with the original repo name
app.repo.replace(/\.git$/, ""), // If that fails, try without .git suffix
];
// Use consistent server identifiers that match documentation
const servers: Record<string, LSPServer.Info> = LSPServer.getServerIds(); // Use "typescript", not "Typescript"
This prevents user confusion and reduces integration issues when the same logical entity has different naming requirements across different systems.
Ensure configurations are conditional, context-aware, and resilient. Use feature flags to control functionality availability rather than instructing systems to avoid certain features. Implement proper fallbacks for missing configuration values and support backward compatibility when introducing new config formats.
Key practices:
Example:
// Good: Conditional tool availability based on feature flag
if (experiments?.morphFastApply !== true) {
tools.delete("edit_file")
}
// Good: Fallback to system language instead of hardcoded default
initializeI18n(context.globalState.get("language") ?? formatLanguage(vscode.env.language))
// Good: Support multiple rule file formats for backward compatibility
const ruleFiles = [".kilocoderules", ".roorules", ".clinerules"]
// Good: Make hardcoded values configurable
const sizeLimit = config.get("sizeLimitFraction") ?? SIZE_LIMIT_AS_CONTEXT_WINDOW_FRACTION
Prefer the consolidated config system over adding new environment variables. Environment variables should only be used for deployment-specific overrides, not as the primary configuration mechanism.
Guidelines:
Config::global().get_param() system for new configuration optionsGOOSE_* environment variables unless absolutely necessary for deployment scenariosExample:
// ❌ Avoid: Adding new environment variables
const GOOSE_RECIPE_RETRY_TIMEOUT_SECONDS: &str = "GOOSE_RECIPE_RETRY_TIMEOUT_SECONDS";
fn get_retry_timeout(retry_config: &RetryConfig) -> Duration {
let timeout_seconds = env::var(GOOSE_RECIPE_RETRY_TIMEOUT_SECONDS)
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(DEFAULT_RETRY_TIMEOUT_SECONDS);
Duration::from_secs(timeout_seconds)
}
// ✅ Prefer: Use config system with parameter passing
fn get_retry_timeout(retry_config: &RetryConfig, config_timeout: Option<u64>) -> Duration {
let timeout_seconds = retry_config.timeout_seconds
.or(config_timeout)
.unwrap_or(DEFAULT_RETRY_TIMEOUT_SECONDS);
Duration::from_secs(timeout_seconds)
}
// At call site:
let config = Config::global();
let timeout = config.get_param("RETRY_TIMEOUT_SECONDS").unwrap_or(DEFAULT_RETRY_TIMEOUT_SECONDS);
get_retry_timeout(&retry_config, Some(timeout))
This approach reduces environment variable sprawl while maintaining flexibility for deployment-specific configuration through the existing config system.
Replace generic, ambiguous, or magic identifiers with descriptive, specific names that clearly communicate intent and avoid confusion.
Key principles:
Examples:
// Bad: Generic time-based ID
let execution_id = format!("exec_{}", SystemTime::now().duration_since(UNIX_EPOCH));
// Good: UUID-based ID
let execution_id = format!("exec_{}", Uuid::new_v4());
// Bad: Magic number with comment
command.creation_flags(0x08000000); // CREATE_NO_WINDOW flag
// Good: Named constant
const CREATE_NO_WINDOW: u32 = 0x08000000;
command.creation_flags(CREATE_NO_WINDOW);
// Bad: String constants
const EXECUTION_MODE_PARALLEL: &str = "parallel";
const EXECUTION_MODE_SEQUENTIAL: &str = "sequential";
// Good: Enum
enum ExecutionMode {
Parallel,
Sequential,
}
This approach improves code maintainability, reduces ambiguity, and makes the codebase more self-documenting.
Choose names that clearly communicate purpose, type, and intent rather than generic or ambiguous identifiers. Names should be self-documenting and help other developers understand what the code does without additional context.
Key principles:
filePaths instead of files, selectedGroupIndex instead of selectedGroup)getKiloBaseUri instead of KiloBaseUri)kilocodeToken)Example improvements:
// Instead of generic names:
const cache = new Map<string, Promise<string>>() // unclear what string represents
function KiloBaseUri(options: ApiHandlerOptions) // unclear if this gets, sets, or creates
// Use descriptive names:
const cache = new Map<string, Promise<string>>() // with comment: kilocodeToken -> model promise
function getKiloBaseUri(options: ApiHandlerOptions) // clearly indicates this retrieves a URI
// Parameter clarity:
files?: string[] // ambiguous
filePaths?: string[] // clearly indicates these are file paths
This approach reduces cognitive load, improves code maintainability, and makes the codebase more accessible to new team members.
Avoid generic catch-all error handling that masks important failures. Instead, be selective about which errors to handle locally versus letting them bubble up to higher-level handlers. When you do handle errors locally, implement safe defaults and use robust parsing methods.
Key principles:
safeJsonParse instead of raw JSON.parse()Example of intentional error handling:
// Bad: Generic catch that hides all errors
try {
const result = await response.json();
return result;
} catch (error) {
return { success: false }; // Masks what actually went wrong
}
// Good: Let parsing errors bubble up, handle specific conditions
const result = await safeJsonParse(response);
// Handle specific recoverable errors
if (response.status === 529 || response.status === 503) {
// Retry logic for service overload
return retryRequest();
}
// For security scans, default to safe behavior on failure
try {
const scanResult = await scanRecipe(recipeConfig);
setHasSecurityWarnings(scanResult.has_security_warnings);
} catch (error) {
setHasSecurityWarnings(false); // Safe default, show generic warning
}
Organize tests for maximum clarity and maintainability by leveraging pytest features and proper test structure. Split complex tests into focused, single-purpose test cases rather than testing multiple scenarios in one function. Use pytest fixtures for setup and cleanup instead of manual resource management, and prefer parameterization for testing multiple inputs.
Key practices:
tmp_path fixture so that it’s automatically cleaned up”dummy_embedder() as a helper function”assert”Example of good test structure:
@pytest.mark.parametrize("module", [dspy.Predict, dspy.ChainOfThought])
def test_color_classification_using_enum(module):
# Single focused test case with parameterization
def test_file_access_control(tmp_path):
# Use pytest fixture for automatic cleanup
testfile_path = tmp_path / "test_file.txt"
This approach makes tests more readable, maintainable, and reliable while following pytest best practices.
Replace hardcoded string matching and magic values with proper configuration enums or flags. This improves maintainability, reduces errors, and makes configuration behavior explicit and type-safe.
Instead of checking string content for configuration decisions:
// Avoid: hardcoded string matching
{!prompt?.includes('SECURITY WARNING') && (
<Button onClick={() => handleButtonClick(ALWAYS_ALLOW)}>
Always Allow
</Button>
)}
Use explicit configuration enums or flags:
// Better: explicit configuration enum
enum ConfirmationType {
STANDARD = 'standard',
SECURITY_WARNING = 'security_warning',
CRITICAL = 'critical'
}
{confirmationType !== ConfirmationType.SECURITY_WARNING && (
<Button onClick={() => handleButtonClick(ALWAYS_ALLOW)}>
Always Allow
</Button>
)}
Similarly, for platform-specific configurations, use structured approaches rather than inline conditionals. This pattern prevents bugs from typos in string matching, makes the configuration intent clear to other developers, and enables better tooling support through TypeScript’s type system.
Always validate configuration parameters for type, range, and reasonable values before use. Provide safe defaults for optional settings and prefer explicit parameter passing over runtime environment variable modification.
Key practices:
Example:
# Good: Validate and use safe defaults
recursion_limit = int(os.getenv("AGENT_RECURSION_LIMIT", "25"))
if recursion_limit <= 0:
raise ValueError("Recursion limit must be greater than zero")
logger.info(f"Recursion limit is set: {recursion_limit}")
# Good: Pass as parameters instead of environment modification
return AzureChatOpenAI(
api_version=llm_config.get("api_version"),
api_key=llm_config.get("api_key"),
azure_endpoint=llm_config.get("base_url")
)
# Avoid: Runtime environment modification
os.environ.update({"AZURE_OPENAI_API_KEY": api_key}) # Not recommended
Choose variable, function, and constant names that clearly express their purpose and eliminate the need for explanatory comments. Break down complex expressions into well-named intermediate variables rather than relying on comments to explain the logic.
For example, instead of:
// Use explicit hasEnvVars if provided, otherwise fall back to checking step3Content
const hasConfiguration = hasEnvVars !== undefined ? hasEnvVars : step3Content !== null;
Use descriptive intermediate variables:
const hasConfigurationContent = step3Content !== null;
const shouldShowConfigurationSteps = hasEnvVars ?? hasConfigurationContent;
This principle also applies to extracting repeated string literals into named constants. Instead of using ‘New Chat’ multiple times throughout the code, define a constant like DEFAULT_CHAT_TITLE = 'New Chat' to make the intent clear and improve maintainability.
Keep persistent user configuration separate from transient state, setup flags, and derived values. Persistent configuration should only contain user-defined settings that need to be saved across sessions. Transient state like cached detection results, setup completion flags, or runtime-derived values should be stored separately using dedicated state management or separate files.
For example, instead of adding setup state to the main config:
type Config struct {
Providers map[models.ModelProvider]Provider `json:"providers,omitempty"`
Agents map[AgentName]Agent `json:"agents,omitempty"`
SetupComplete bool `json:"setupComplete,omit"` // ❌ Don't mix setup state with config
}
Extract setup functionality into its own module or store in app state:
// ✅ Keep config clean of transient state
type Config struct {
Providers map[models.ModelProvider]Provider `json:"providers,omitempty"`
Agents map[AgentName]Agent `json:"agents,omitempty"`
}
// ✅ Store transient state separately
type AppState struct {
detectedTimeFormat *bool // cached detection result
setupComplete bool // setup state
}
This separation improves maintainability, prevents config bloat, and makes it clear which data persists vs which is computed or temporary.
Prefer Node.js native fetch API over external HTTP client libraries like node-fetch when the target Node.js version supports stable native functionality. While fetch is available from Node.js 18+, it’s considered stable from version 21 onwards.
Before adding HTTP client dependencies, evaluate:
Example of unnecessary dependency:
// Avoid when targeting Node.js >= 21
"dependencies": {
"node-fetch": "3.3.2" // Remove if native fetch suffices
}
This reduces bundle size, eliminates potential security vulnerabilities from external packages, and leverages platform-native optimizations. Only retain HTTP client libraries when they provide essential features not available in the native fetch API or when targeting older Node.js versions where native fetch is unstable.
Ensure AI model configurations and related documentation use precise terminology and provide clear, complete setup instructions without overwhelming users.
When documenting AI models, LLMs, and related infrastructure:
Use precise terminology: Distinguish between “parameters” (learned values) and “hyperparameters” (values that control the learning process). For example, demonstration examples are parameters, while max_labeled_demos and temperature are hyperparameters.
Provide complete configuration examples: Include all required parameters, environment variables, and credentials users need. For instance, when documenting model clients, specify required connection parameters and API keys:
# Good: Complete configuration
lm = dspy.Snowflake(
model="mixtral-8x7b",
credentials={
"account": "your_account",
"user": "your_username",
"password": "your_password",
"warehouse": "your_warehouse"
}
)
# Environment variables required:
# OPENAI_API_KEY="your-openai-api-key"
Start simple, then expand: Begin with essential configurations before introducing advanced options. Avoid overwhelming users with complex features upfront - start with basic functionality like llms.txt before introducing llms-full.txt.
Include performance considerations: Document recommended settings for better performance, such as async configurations and optimal hyperparameters:
dspy.settings.configure(lm=lm, async_capacity=16) # max 16 concurrent DSPy programs
dspy_model = dspy.asyncify(dspy.ChainOfThought("question -> answer"))
This approach ensures developers can successfully configure AI systems while understanding the underlying concepts and performance implications.
Focus on efficient memory usage and algorithm selection while preserving functionality. Apply these optimization techniques:
Memory optimization:
Vec::with_capacity(known_size)Algorithm efficiency:
// Instead of: lines.iter().rev().take(100).rev().copied().collect()
let start = lines.len().saturating_sub(100);
let result = lines[start..].join("\n");
// Instead of: tool_name.starts_with(PREFIX)
// Use: self.tool_map.contains_key(tool_name)
Remember that correctness takes priority over performance optimizations. Avoid truncating or modifying data in ways that could break downstream functionality, even if it improves performance metrics.
Make CI and build configuration deterministic by explicitly selecting tool versions and target environments, and by ensuring monorepo config paths match what downstream generators expect.
Apply this by:
uv/Python install steps target the intended venv explicitly (or deterministically discover it), rather than inheriting an existing/global VIRTUAL_ENV or relying on auto-activation.path) so config-driven steps (like docs/provider discovery) can find the expected files.Example (targeting the correct venv with uv):
# Prefer deterministic venv selection; keep it explicit to avoid global overlap.
VIRTUAL_ENV=.venv uv pip install dist/*.whl
# If you prefer deriving it, ensure your script finds/creates the same venv
# that the rest of the pipeline uses, then pass VIRTUAL_ENV accordingly.
uv venv
VIRTUAL_ENV=.venv uv pip install dist/*.whl
Example (monorepo package config):
# Ensure `path` reflects the package root the build/docs tooling expects.
- name: toolbox-langchain
repo: googleapis/mcp-toolbox-sdk-python
path: . # (not a nested subdir) when the generator expects package-root contents
Implement provider-specific logic when integrating different AI services, as each provider has unique requirements for message formatting, API endpoints, validation rules, and optimization strategies.
Different AI providers require distinct handling approaches:
Message Role Handling: Transform message roles based on provider requirements. For example, Baidu requires system messages to be converted to assistant/user roles and maintains strict alternating patterns, while Google converts system roles to user roles.
// Provider-specific message role transformation
const messages = options.messages.map((v) => ({
role: v.role === "system" ? "assistant" : v.role, // Baidu-specific
content: getMessageTextContent(v),
}));
// vs Google-specific transformation
role: v.role.replace("assistant", "model").replace("system", "user"),
API Path Construction: Use provider-specific URL patterns and model handling. Azure requires deployment names in URLs, while Gemini needs dynamic model injection into paths.
// Provider-specific path handling
if (modelConfig.providerName == ServiceProvider.Azure) {
chatPath = this.path(`/deployments/${deploymentName}/chat/completions`);
} else {
chatPath = this.path(OpenaiPath.ChatPath);
}
Model-Specific Optimization: Apply provider-specific models for different operations like summarization, using each provider’s most suitable and cost-effective options rather than defaulting to a single model across all providers.
This approach ensures compatibility, optimal performance, and proper functionality across different AI service providers while maintaining clean, maintainable code.
When performing database migrations or schema changes, use containerized environments to ensure isolation and comprehensive testing. This approach prevents migration issues from affecting development environments and allows for reliable rollback scenarios.
Containerized database migrations provide several benefits:
Example approach for migrating from file-based storage to SQLite:
# Use container-use to create isolated environment
container-use stdio
# Within the container, perform migration steps:
# 1. Set up SQLite database schema
# 2. Migrate data from file-based storage
# 3. Run comprehensive tests
# 4. Validate data integrity
This practice is especially important when transitioning between storage mechanisms (like moving from file-based to database storage) where data integrity and application functionality must be thoroughly validated before deployment.
Always validate configuration values against system limits and constraints, implementing automatic adjustment when values exceed acceptable bounds. This prevents runtime errors and ensures configurations remain within operational parameters.
When setting configuration values that have system-imposed limits (like token counts, memory limits, or API constraints), implement validation logic that checks against maximum allowed values and automatically adjusts when necessary. For user-facing configuration displays, ensure accuracy by showing actual values rather than assumptions, and consider platform-specific variations.
Example implementation:
// Validate and auto-adjust configuration values against system limits
useEffect(() => {
if (isFeatureSupported && systemInfo?.maxLimit && userConfigValue > systemInfo.maxLimit) {
setConfigurationField("configKey", systemInfo.maxLimit || DEFAULT_FALLBACK_VALUE)
}
}, [isFeatureSupported, userConfigValue, systemInfo?.maxLimit, setConfigurationField])
// For display, show actual vs default values with platform awareness
const displayValue = userHasCustomized ? `${actualValue} [custom]` : `${defaultValue} [default]`
const platformKey = isMac ? "⌘" : "Ctrl"
This approach prevents configuration-related failures and provides users with accurate information about their current settings.
Ensure all configuration documentation accurately reflects actual system behavior, available options, and correct command syntax. Configuration errors in documentation lead to broken user setups and erode trust.
Key areas to verify:
goose session not goose session start)cu version vs cu --version)Example of problematic documentation:
# Incorrect - this command doesn't exist
ALPHA_FEATURES=true goose session start
# Correct - verified working command
ALPHA_FEATURES=true goose session
Before publishing configuration documentation, test each command and verify each described behavior actually works as documented. Remove or clearly mark any configuration options that are planned but not yet implemented.
Different AI providers and models have unique requirements for input processing, output filtering, and API parameters that must be implemented correctly. When working with AI APIs, research and implement provider-specific handling rather than assuming uniform behavior across all providers.
Key considerations:
filterThinkingTags(block.text) for certain models)max_tokens to prevent output truncation, especially for models like DeepSeek R1Example implementation:
// Provider-specific parameter handling
const requestOptions = {
model: model.id,
messages: openAiMessages,
max_tokens: maxOutputTokens, // Required by Fireworks API
// ... other provider-specific params
}
// Provider-specific content filtering
const processedContent = isSpecialModel
? filterThinkingTags(block.text)
: block.text
Before implementing generic solutions, verify whether the target AI provider has documented requirements or behavioral differences that need accommodation.
Avoid fixed delays for telemetry flushing. Instead, make flushing conditional on whether telemetry endpoints are configured and use dynamic timeouts when possible.
Fixed sleep durations for telemetry flushing create unnecessary delays when no telemetry is configured and don’t guarantee actual completion of data export. This is particularly problematic in CLI tools where delays accumulate across multiple runs.
Implementation approach:
Example:
// Instead of fixed delays everywhere:
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
std::thread::sleep(std::time::Duration::from_millis(500));
// Use conditional flushing:
let should_flush = std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").is_ok()
|| config.get_param::<String>("otel_exporter_otlp_endpoint").is_ok();
if should_flush {
shutdown_otlp_with_timeout(Duration::from_secs(2)).await;
}
This approach improves performance for users without telemetry configured while ensuring proper cleanup when telemetry is enabled.
Add clear documentation for code elements that aren’t immediately self-explanatory to improve readability and maintainability. This includes replacing magic numbers with named constants, adding explanatory comments for complex types, and ensuring documentation remains consistent and synchronized across different contexts.
Key practices:
const LINE_LIMIT: usize = 2000; instead of using 2000 directlyExample for type documentation:
/// A message stream yields partial text content but complete tool calls,
/// all within the Message object. So a message with text will contain
/// potentially just a word of a longer response
pub type MessageStream = Pin<...>;
This practice helps new team members understand the codebase faster and reduces the cognitive load when reviewing or modifying code.
Choose appropriate version constraints in package.json based on stability requirements and risk tolerance. Use tilde (~) for patch-level updates when you want stability but need bug fixes, caret (^) for minor updates when you can tolerate feature additions, or exact versions for maximum control. For critical dependencies requiring precise version control, consider using npm overrides to enforce specific versions across the dependency tree.
Example:
{
"dependencies": {
"@mcp-ui/client": "~5.3.1" // Allow patches only
},
"overrides": {
"@mcp-ui/client": "5.3.1" // Force exact version if needed
}
}
The choice between “~5.3.1” (patches allowed) versus “5.3.1” (exact) should reflect your project’s stability needs and tolerance for automatic updates.
Identify and mitigate costly operations that can significantly impact performance. This includes CPU-intensive processing, expensive I/O operations, and repeated function calls that involve file system access or complex computations.
When you encounter performance bottlenecks:
Example of avoiding expensive operations:
// Avoid: Multiple expensive calls
const { mode, apiConfiguration, language } = await this.getState()
const { experiments } = await this.getState() // Expensive I/O operation called twice
// Prefer: Single expensive call with full destructuring
const {
mode,
apiConfiguration,
language,
experiments
} = await this.getState()
// Or disable expensive features when cost outweighs benefit:
// context = await this.addAST(context) // Disabled: uses too much CPU for Swift
Always weigh the performance cost against the actual benefit provided, especially for operations involving file I/O, network calls, or intensive computations.
Avoid hard-coding configuration values directly in source files. Instead, externalize them using environment variables, configuration files, or external resources. This improves maintainability, enables environment-specific settings, and reduces bundle sizes.
For runtime configuration, use environment variables:
// Instead of hard-coding:
id: 'ep-20250627155918-4jmhg'
// Use environment variables:
id: process.env.MODEL_ID
For build-time configuration, consider external dependencies:
// Instead of bundling large resources:
const minifiedCSS = cleanCSS.minify(reportCSS).styles;
// Use external CDN resources in modern.config.js:
// https://unpkg.com/@ui-tars/visualizer/dist/report/
This approach enables different configurations per environment, reduces code coupling, and keeps sensitive or environment-specific values out of the codebase.
Always provide meaningful keys for React components and fragments to ensure proper rendering and re-rendering behavior. Use composite keys when component identity depends on multiple values, and include keys even for Fragment components when rendering lists.
For components that need to re-render based on multiple state changes, create composite keys:
<MarketplaceInstallModal
key={`install-modal-${item.id}-${installModalVersion}`}
// other props
/>
For Fragment components in lists, always include a key prop:
{PROVIDERS.map(({ value, label }, i) => (
<Fragment key={value}>
<SelectItem value={value}>
{label}
</SelectItem>
</Fragment>
))}
This prevents React from incorrectly reusing components and ensures predictable rendering behavior, especially when component state or props change frequently.
Replace busy-wait polling loops with event-driven async patterns using asyncio.Event() or similar synchronization primitives. Polling loops that continuously check state variables waste CPU cycles and block the event loop, while event-driven patterns allow the thread to yield control until the condition is actually met.
Look for patterns like:
# Avoid: Busy-wait polling
while self.state.paused:
await asyncio.sleep(0.1) # Still wastes cycles checking every 100ms
Replace with event-driven patterns:
# Prefer: Event-driven waiting
self._pause_event = asyncio.Event()
# In the waiting code:
await self._pause_event.wait() # Blocks until event is set, no polling
# In the control code:
def pause(self):
self.state.paused = True
self._pause_event.clear()
def resume(self):
self.state.paused = False
self._pause_event.set()
This approach eliminates CPU spinning, allows proper async task isolation (each task can have its own events), and removes the need for redundant state variables when the event itself serves as the synchronization mechanism. Consider removing duplicate state tracking when the event primitive provides the same information.
Add comments that explain WHY implementation decisions were made, not just WHAT the code does. This is especially important for backwards compatibility hacks, workarounds, non-obvious logic checks, and temporary solutions.
For backwards compatibility measures, include:
For complex logic checks, explain the underlying business reason or technical constraint that necessitates the check.
Example:
# Backwards compatibility hack introduced in v2.1.0 (Dec 2024)
# Maps old context_id system to new server-based sessions
# TODO: Remove after v3.0.0 when all clients migrate to new API
self._context_to_session: dict[str, tuple[str, str]] = {}
# Check if instance is Component subclass (but not Component itself)
# Required because we manually create Component instances from user dicts
# which need compilation/parsing, unlike pre-built Component classes
if isinstance(instance, type) and issubclass(instance, Component):
This practice helps future maintainers understand the codebase evolution and make informed decisions about refactoring or removing temporary measures.
When documenting logging configuration parameters, always provide the complete list of available log level options and use consistent naming conventions. This ensures developers understand all available choices and prevents confusion from incomplete documentation.
Log levels should be documented in lowercase format consistently across all interfaces (CLI, environment variables, configuration files). When a parameter accepts log level values, explicitly list all valid options rather than showing only the default.
Example:
| `--log-level` | `error` | String | Set the logging level. Possible values: `debug`, `info`, `warning`, `error`, `critical`. |
This practice helps developers make informed decisions about logging configuration and ensures consistency across different parts of the system documentation.
When documenting database configuration or setup procedures, provide specific, actionable instructions with clear verification steps. Always specify which database backend is being used and include concrete examples for verification.
Key practices:
Example of good database verification documentation:
5. To verify the configuration, create any flow using the Langflow UI or API, and then query your database to confirm new tables and activity.
* Query the database container:
```
docker exec -it <postgres-container> psql -U langflow -d langflow
```
* Use SQL:
```
SELECT * FROM pg_stat_activity WHERE datname = 'langflow';
```
This approach ensures users can successfully configure and verify their database setup, reducing support issues and improving the development experience.
Use proper heading hierarchy instead of bold text formatting when documenting observability features like monitoring, failure points, and telemetry. This improves navigation, readability, and maintains consistent documentation structure across observability-related content.
Instead of using bold text for section organization:
**Database Failure**:
* **Impact**: Disrupts flow retrieval, saving, user authentication...
* **Mitigation**: Use a replicated PostgreSQL setup...
**File System Issues**:
* **Impact**: Concurrency issues in file caching...
Use proper heading hierarchy:
### Database failure
* **Impact**: Disrupts flow retrieval, saving, user authentication...
* **Mitigation**: Use a replicated PostgreSQL setup...
### File system issues
* **Impact**: Concurrency issues in file caching...
This approach makes observability documentation more scannable, enables proper table of contents generation, and follows standard documentation practices. Apply this consistently across monitoring guides, troubleshooting sections, telemetry documentation, and failure analysis content.
When designing concurrent systems, implement comprehensive safety patterns that handle resource lifecycle management, race conditions, and proper cleanup mechanisms. This includes setting resource limits to prevent exhaustion, implementing timeout-based cleanup for idle resources, and handling database race conditions with proper rollback and retry logic.
Key patterns to implement:
class ResourceManager:
def __init__(self):
self.resources_by_key = {} # Group resources by identity
self._cleanup_task = asyncio.create_task(self._periodic_cleanup())
async def _periodic_cleanup(self):
"""Periodically clean up idle resources."""
while True:
await asyncio.sleep(CLEANUP_INTERVAL)
await self._cleanup_idle_resources()
async def get_resource(self, key, params):
# Check limits before creating new resources
if len(self.resources_by_key.get(key, {})) >= MAX_RESOURCES_PER_KEY:
# Remove oldest resource
await self._cleanup_oldest_resource(key)
async def create_resource(name, session):
try:
# Check if resource exists
existing = await get_resource_by_name(name, session)
if existing:
return existing
# Create new resource
resource = Resource(name=name)
session.add(resource)
await session.commit()
return resource
except IntegrityError:
# Handle race condition - another worker created it
await session.rollback()
existing = await get_resource_by_name(name, session)
if existing:
return existing
raise # Re-raise if no resource found after rollback
asyncio.gather() to test real concurrent behavior
@pytest.mark.asyncio
async def test_concurrent_resource_creation():
"""Test multiple concurrent calls handle race conditions properly."""
tasks = [
create_resource("shared_name", session1),
create_resource("shared_name", session2)
]
results = await asyncio.gather(*tasks, return_exceptions=True)
# Verify both succeed or handle conflicts gracefully
Always consider the impact of automatic resource cleanup on user experience and provide clear boundaries for resource limits to prevent unexpected behavior disruptions.
Avoid common concurrency anti-patterns that lead to race conditions, deadlocks, and unreliable behavior. Use structured approaches instead of ad-hoc solutions.
Key anti-patterns to avoid:
Preferred approaches:
drop() when neededExample:
// Anti-pattern: Manual buffer management with select!
select! {
n = stdout_reader.read_until(b'\n', &mut stdout_buf) => {
// Risk of losing last chunk of data
}
}
// Better: Use streams
let stdout_stream = LinesStream::new(BufReader::new(stdout).lines());
let stderr_stream = LinesStream::new(BufReader::new(stderr).lines());
// Drive streams to completion without manual buffer management
// Anti-pattern: Wrong lock type
pub(super) extension_manager: Mutex<ExtensionManager>, // Blocks concurrent readers
// Better: Allow concurrent reads
pub(super) extension_manager: RwLock<ExtensionManager>, // Multiple readers, single writer
Ensure sensitive data like API keys, passwords, and encryption keys are stored securely and never exposed in code, configuration files, or documentation. This prevents credential leakage and unauthorized access to external services and systems.
Key practices:
Example secure configuration:
# Good: Reference secrets from secure storage
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: api-secrets
key: openai-key
- name: LANGFLOW_SECRET_KEY
valueFrom:
secretKeyRef:
name: langflow-secrets
key: secret-key
Example documentation:
# Good: Truncated example
LANGFLOW_SECRET_KEY=dBuu...2kM2_fb
# Bad: Full credential exposed
LANGFLOW_SECRET_KEY=dBuuuB_FHLvU8T9eUNlxQF9ppqRxwWpXXQ42kM2_fb
This practice is especially critical in production environments where credential exposure can lead to data breaches, unauthorized system access, and compromise of connected services.
Ensure that names accurately reflect their purpose and maintain consistency with established patterns in the codebase. Method names should clearly indicate their behavior - avoid misleading conventions when they don’t match the actual functionality. Similarly, maintain consistent naming patterns across similar contexts.
For example, avoid using “set” prefixes for methods that don’t actually set a value:
// Misleading - implies setting a value
setNotificationDismissed: (notificationId: string) => void
// Clear - accurately describes the action
markNotificationAsDismissed: (notificationId: string) => void
Also ensure consistency in organizational naming patterns:
// Inconsistent
title: "UI/Badge" // in Badge.stories.tsx
title: "Component/Button" // in Button.stories.tsx
// Consistent
title: "Component/Badge" // matches established pattern
title: "Component/Button"
This approach helps maintain code readability and reduces confusion for team members working across different parts of the codebase.
Large files with multiple responsibilities should be broken down into focused, single-responsibility modules to improve maintainability and avoid tight coupling. When a file becomes difficult to navigate or contains unrelated functionality, extract logical components into separate files or classes.
Key indicators for refactoring:
Example refactoring approach:
// Instead of a large BrowserSession.ts with everything:
// Break into focused modules:
// - ChromeExecutableManager.ts (for ensureChromiumExists, getDetectedChromePath)
// - BrowserConnectionManager.ts (for connection logic)
// - BrowserSession.ts (core session management only)
// Instead of inheritance when not needed:
export class OcaHandler extends LiteLlmHandler { // Avoid this
}
// Prefer composition:
export class OcaHandler {
constructor(private authManager: OcaTokenManager) {}
}
When refactoring, make incremental changes - move existing code to new files without changing functionality simultaneously. Separate platform-specific code paths into dedicated modules (like host-providers) rather than mixing them with generic logic.
When you notice repeated logic or functions that could be shared across multiple files, extract them into dedicated utility files. This improves code organization, reduces duplication, and minimizes merge conflicts.
Key principles:
Example:
// Instead of adding to existing file
// src/core/prompts/system.ts
function getMorphInstructions(cwd: string, supportsComputerUse: boolean, settings?: Record<string, any>): string {
// implementation
}
// Extract to dedicated utility
// src/utils/morph-instructions.ts
export function getMorphInstructions(cwd: string, supportsComputerUse: boolean, settings?: Record<string, any>): string {
// implementation
}
This approach keeps files focused, reduces the likelihood of merge conflicts, and makes shared functionality more discoverable and maintainable.
Prefer reusable message types over single-purpose request/response pairs to reduce API bloat and improve maintainability. Avoid creating dedicated “Response” types when the return value can be a plain, reusable struct. Merge identical request types and leverage common message patterns like StringRequest or EmptyRequest where appropriate.
Key principles:
Example:
// Avoid: Single-use response type
rpc getRecordingStatus(GetRecordingStatusRequest) returns (GetRecordingStatusResponse);
// Prefer: Reusable plain type
rpc getRecordingStatus(EmptyRequest) returns (RecordingStatus);
// Avoid: Duplicate request types
message RestartMcpServerRequest {
Metadata metadata = 1;
string server_name = 2;
}
// Prefer: Reuse common type
rpc restartMcpServer(StringRequest) returns (Empty);
This approach creates cleaner APIs with fewer message types while maintaining the same functionality.
Every code change, whether it’s a new feature, bug fix, or refactoring, must include corresponding tests. This ensures code quality, prevents regressions, and maintains system reliability.
When adding new functionality:
// New feature: paste detection logic
it('should process a paste as a single event', () => {
renderHook(() => useKeypress(onKeypress, { isActive: true }));
const pasteText = 'hello world';
act(() => {
stdin.paste(pasteText);
if (isLegacy) {
vi.advanceTimersByTime(35);
}
});
// Test the new behavior
});
When fixing bugs, write tests that would have failed before the fix:
// Test for race condition fix
it('should handle concurrent update checks without race conditions', async () => {
// This test would have failed before the fix
updateNotifier.mockReturnValue({
fetchInfo: vi.fn().mockResolvedValue({ current: '1.1.0', latest: '1.0.0' }),
});
// Verify the fix works
});
Tests serve as documentation of expected behavior and catch regressions during future changes. They should cover the main functionality, edge cases, and error conditions of the code being modified.
Ensure naming consistency across all contexts where an identifier appears - configuration files, code enums, documentation, and user interfaces. Names should be semantically clear and distinguish between related but different entities.
When the same concept appears in multiple places, use identical naming:
Prefer simple, unambiguous names that avoid unnecessary complexity:
// Good: Consistent across config and code
"selectedAuthType": "oauth" // matches AuthType.OAUTH in code
// Bad: Inconsistent naming
"selectedAuthType": "oauth-personal" // while code uses AuthType.LOGIN_WITH_GOOGLE
For related but distinct entities, use clear semantic distinctions:
When naming conflicts arise, implement graceful resolution strategies that preserve the original simple names for the most common cases while providing clear alternatives for conflicts.
Configure Jest to collect coverage data from all source files, not just those with existing tests, while avoiding test failures due to coverage thresholds. Coverage enforcement should be handled by external reporting tools rather than the test runner itself.
Use comprehensive collectCoverageFrom patterns to include all source files while excluding test files, setup files, and type definitions:
module.exports = {
collectCoverage: true,
collectCoverageFrom: [
"src/**/*.{ts,tsx}",
"!src/**/*.{test,spec}.{ts,tsx}",
"!src/**/tests/**",
"!src/**/__tests__/**",
"!src/setupTests.ts",
"!src/vite-env.d.ts",
"!src/**/*.d.ts",
],
// Remove coverageThreshold to avoid test failures
// Let external tools like codecov handle enforcement
};
This approach provides complete visibility into code coverage across the entire codebase while keeping test execution focused on correctness rather than coverage metrics.
Use explicit type checks instead of just undefined checks to prevent null values from being passed to functions or APIs that don’t expect them. Checking only for undefined can still allow null values to pass through, which may cause runtime errors.
When dealing with optional parameters that should only be included when they have valid values, check for the specific expected type rather than just checking if the value is not undefined.
// ❌ Problematic - allows null to pass through
...(params.seed !== undefined ? { seed: params.seed } : {})
// ✅ Better - ensures only valid numbers are passed
...(typeof params.seed === 'number' ? { seed: params.seed } : {})
For truly optional environment variables or configuration values, avoid unnecessary fallbacks that might mask configuration issues:
// ❌ Unnecessary fallback for optional values
OPTIONAL_KEY: process.env.OPTIONAL_KEY || ''
// ✅ Let optional values remain undefined
OPTIONAL_KEY: process.env.OPTIONAL_KEY
Always verify that parent objects and properties exist before accessing nested properties or calling methods on them. Use optional chaining (?.) only when the parent object might genuinely be null or undefined, not as a blanket safety measure for guaranteed values. When values can be undefined, provide meaningful defaults rather than arbitrary fallbacks.
Good examples:
// When parent might be undefined
if (navigator && navigator.userAgent) {
const isChrome = navigator.userAgent.indexOf("Chrome") >= 0
}
// When property might be undefined
const cachedTokens = chunk.usage.prompt_tokens_details?.cached_tokens || 0
// When request is guaranteed to exist
if (request.options?.canSelectMany !== undefined) { // not request?.options
Avoid:
// Unnecessary optional chaining on guaranteed values
request?.options?.canSelectMany // when request is never null
// Accessing without null checks
const isChrome = navigator.userAgent.indexOf("Chrome") >= 0 // navigator might be undefined
// Arbitrary defaults that cause calculation errors
let effectiveOutputPrice = modelInfo.outputPrice || 0 // should use meaningful default
This prevents runtime errors from null reference exceptions and ensures more predictable behavior when handling optional data.
Choose names that clearly communicate the purpose, behavior, and intent of variables, methods, classes, and interfaces. Avoid ambiguous or misleading names that require additional context to understand.
Names should be self-documenting and accurately reflect what the entity represents or does. Consider the actual behavior and usage patterns when naming, not just the initial implementation.
Examples of improvements:
SupportedIDE → DetectedIde (clarifies this represents the current IDE, not all supported ones)ActiveFileSchema → openFilesSchema with filePath → activeFilePath (better reflects the expanding scope)source → kind (more semantic and extensible for different types)interactive → forceInteractive (clarifies it only affects behavior when -p flag is present)is_loop → loopDetected (more targeted and descriptive)When naming conflicts arise or behavior changes, prioritize semantic accuracy over maintaining existing names. The name should help future developers understand the code without needing to read the implementation.
All errors must be explicitly handled through catching, logging, or user feedback. Silent error suppression makes debugging impossible and creates poor user experiences.
Always do one of the following:
.catch() handlers to promises to prevent unhandled rejectionsExample of proper error handling:
// Bad: Silent failure
checkForUpdates().then((info) => {
// handle success
});
// Good: Explicit error handling
checkForUpdates().then((info) => {
// handle success
}).catch((error) => {
console.error('Update check failed:', error.message);
});
// Bad: Removing error logs
} catch (error) {
// Ignore clipboard image errors
}
// Good: Maintain error visibility
} catch (error) {
console.error('Error handling clipboard image:', error);
}
This ensures errors are visible to developers during debugging and users understand when operations fail, enabling proper troubleshooting and recovery.
Use specific, unambiguous names for AI providers and models to prevent confusion when working with multiple AI services. Avoid generic names that could be mistaken for other providers or create ambiguity about the underlying service.
When naming AI providers:
Example from discussions:
// Before: Confusing connection between Oracle and LiteLLM
// After: Rename to "oca_" for clarity
// Before: Generic interface name
interface HuaweiCloudMaaSHandlerOptions {
huaweiCloudMaasApiKey?: string
}
// After: Huawei-specific naming
interface HuaweiCloudMaaSHandlerOptions {
huaweiCloudMaasApiKey?: string // Clear this is Huawei-specific
}
// Include explicit provider suffixes for discoverability
"moonshotai/Kimi-K2-Instruct:groq": {
// model configuration
}
This prevents developer confusion, improves code maintainability, and makes the relationship between code and AI services immediately clear.
Before choosing between sequential awaits and parallel execution (Promise.all), carefully analyze whether operations have dependencies that require specific execution order. Operations that depend on each other’s results or shared state must be executed sequentially to prevent race conditions.
When operations must complete in a specific order (e.g., setting backend context before fetching data), use sequential awaits:
// Sequential - when second operation depends on first
await AccountServiceClient.setUserOrganization({ organizationId })
await fetchCreditBalance() // Needs correct backend context from above
When operations are independent and can run concurrently, use Promise.all for better performance:
// Parallel - when operations are independent
await Promise.all([getUserCredits(), getUserOrganizations()])
The key is understanding the data flow and dependencies between async operations. Don’t optimize for speed at the expense of correctness - a race condition where “the subsequent call might execute with the wrong backend context” can cause subtle bugs that are difficult to debug.
Choose between null and undefined based on semantic intent rather than convenience. Use null when operations can explicitly fail and you want to represent that failure state, allowing consumers to handle it appropriately. Use optional properties (?) when a value may simply not be provided or initialized.
Avoid redundant null safety patterns when operations are guaranteed to succeed, as this can create unnecessary complexity and potential regressions.
Example:
// Good: null represents explicit failure state
interface ExtensionState {
totalTasksSize: number | null // null when operation fails
}
// Good: undefined represents uninitialized/optional state
interface ComponentProps {
targetSection?: string // may not be provided
}
// Avoid: redundant fallback when find() will always succeed
const defaultTab = SETTINGS_TABS.find(tab => tab.id === "general")?.id ?? SETTINGS_TABS[0].id
This approach makes the code’s intent clearer and helps consumers understand how to handle different null states appropriately.
Place code at the appropriate abstraction level and extract complex logic to dedicated modules. Large files like App.tsx and gemini.tsx should focus on their core responsibilities, with specific functionality moved to specialized components or utility files.
When to extract:
When to move to lower abstraction:
Example:
// Instead of handling keystrokes directly in App.tsx:
if (key.ctrl && input === 'o') {
setShowErrorDetails((prev) => !prev);
} else if (key.ctrl && input === 't') {
// complex logic...
}
// Extract to keystrokeHandler.ts:
const keystrokeHandlers = [
{
input: 'o',
ctrl: true,
handler: () => setShowErrorDetails((prev) => !prev),
},
// ...
];
This approach keeps files focused, improves testability, and makes the codebase more maintainable by ensuring each module has a clear, single responsibility.
When multiple operations can execute concurrently (e.g., multiple keystrokes in the same React event loop, simultaneous async calls), ensure they don’t operate on stale state or create race conditions. Use centralized state management patterns like reducers, proper synchronization flags, and avoid direct state manipulation from concurrent contexts.
Key strategies:
this.flushing = true immediately after condition checks, not inside async operationsExample from vim input handling:
// ❌ Problematic: Direct state reading in concurrent context
const getCurrentOffset = useCallback(() => {
const lines = buffer.lines; // Could be stale if multiple keystrokes processed
// ... calculate offset
}, [buffer]);
// ✅ Better: Use reducer for sequential operations
const [state, dispatch] = useReducer(vimReducer, initialState);
// Operations go through reducer ensuring proper sequencing
Example from async flag management:
// ❌ Race condition: Flag set inside async operation
async flushToClearcut() {
this.flushing = true; // Too late - race window exists
// ... async work
}
// ✅ Proper: Flag set synchronously after checks
flushIfNeeded() {
if (this.flushing || /* other conditions */) return;
this.flushing = true; // Set immediately after checks pass
this.flushToClearcut().finally(() => this.flushing = false);
}
This prevents bugs where rapid user interactions or concurrent async operations interfere with each other, ensuring predictable behavior even under high-frequency input scenarios.
Prefer early returns, guard clauses, and helper method extraction to reduce nesting levels and improve code readability. Deep nesting makes code harder to follow and understand.
Apply early returns to eliminate unnecessary nesting:
// Instead of:
if (config) {
const promptCommands: SlashCommand[] = [];
// ... more nested logic
}
// Use early return:
if (!config) {
return promptCommands;
}
const promptCommands: SlashCommand[] = [];
// ... logic at top level
Extract complex conditionals into helper methods:
// Instead of nested ternary:
const effectiveAuthType = configuredAuthType ||
(process.env.GOOGLE_GENAI_USE_GCP === 'true'
? AuthType.USE_VERTEX_AI
: process.env.GEMINI_API_KEY
? AuthType.USE_GEMINI
: undefined);
// Use switch or helper method for clarity
Replace magic numbers with named constants:
// Instead of:
await new Promise((res) => setTimeout(res, 200));
// Use:
const PROCESS_KILL_TIMEOUT_MS = 200;
await new Promise((res) => setTimeout(res, PROCESS_KILL_TIMEOUT_MS));
Extract complex logic into focused helper methods rather than embedding it inline. This keeps the main function readable and allows for better testing and reuse.
Maintain backward compatibility when evolving API interfaces by preserving existing method signatures and parameter patterns. When adding new functionality, prefer extending existing interfaces over breaking changes, and use deprecation warnings for obsolete parameters.
Key principles:
get”__init__, which become defaults for __call__. The kwargs passed to __call__ overwrite any defaults from __init__”kwargs and move the deprecated args there, and print a clear warning that it’s deprecated”Example of backward-compatible parameter evolution:
# Before
def __init__(self, model):
self.model = model
# After - maintains compatibility while adding type safety
def __init__(self, embedding_model: Union[str, Callable] = 'text-embedding-ada-002',
embedding_function: Optional[Callable] = None, **kwargs):
# Handle both old and new parameter patterns
self.model = embedding_function or embedding_model
self.kwargs = kwargs
This approach prevents breaking existing user code while enabling clean API evolution and improved developer experience.
Prefer centralized configuration files (settings.json, settings.ts) over environment variables for application settings, especially when organizational control is needed. Avoid hardcoded assumptions about user environments and ensure configuration is loaded at appropriate initialization points.
Environment variables should be reserved for deployment-specific concerns, while user preferences and feature toggles belong in structured configuration files that support organizational policies and are easier to manage across multiple sources.
Example of preferred approach:
// Instead of:
if (process.env.GEMINI_CLI_DISABLE_AUTOUPDATER === 'true') {
return;
}
// Prefer:
if (settings.merged.disableAutoUpdater) {
return;
}
// Load configuration early in initialization:
// Load custom themes from settings
themeManager.loadCustomThemes(settings.merged.customThemes);
This approach enables organizational control through settings.json files, reduces the complexity of merging configuration from multiple sources, and makes configuration more discoverable and maintainable. Additionally, organize reusable configuration interfaces in dedicated files rather than embedding them in component files to support future extensibility and reuse across the application.
When working with upstream codebases, prioritize coding approaches that minimize merge conflicts while maintaining functionality. Keep dependency arrays in consistent order with upstream code, use CSS classes for conditional styling instead of conditional rendering to create smaller diffs, and isolate custom components in separate directories. For example, instead of wrapping large code blocks in conditionals, use className approaches:
// Prefer this - smaller diff, easier merging
<div className={cn("shrink-0", "w-[70px]", { "hidden": options.length < 2 })}>
// Avoid this - creates large indentation diff
{options.length >= 2 && (
<div className="shrink-0 w-[70px]">
// ... large code block
</div>
)}
This approach reduces the likelihood of merge conflicts and makes code reviews easier to follow when syncing with upstream changes.
When documenting network connections (SSH, HTTP, database, etc.), provide clear explanations of all connection parameters, their security implications, and their relationships. Don’t just list placeholders - explain what each parameter represents and why it’s needed.
For connection commands, structure parameter explanations as bulleted lists after the command block. Clarify security-sensitive distinctions (like public vs private keys) and include context about how parameters work together in the network protocol.
Example:
ssh -i PATH_TO_PRIVATE_KEY/PRIVATE_KEY_NAME root@SERVER_IP_ADDRESS
Replace the following:
PATH_TO_PRIVATE_KEY/PRIVATE_KEY_NAME: The path to your private SSH key file that matches the public key you added to your serverSERVER_IP_ADDRESS: Your server’s IP addressThis approach helps developers understand the security model and connection flow, not just the syntax to copy-paste.
All new functionality must include corresponding unit tests. This is especially critical for utility functions, core logic modules, stream processing, data transformation methods, and complex business logic. Without unit tests, code becomes difficult to understand and maintain over time.
Key areas that require unit tests:
Example test structure for a utility function:
// For a model parsing utility
describe('detectModelProvider', () => {
it('should detect anthropic provider for claude models', () => {
expect(detectModelProvider('claude-3-sonnet')).toBe('anthropic');
});
it('should default to openai for unknown models', () => {
expect(detectModelProvider('unknown-model')).toBe('openai');
});
});
When adding tests, ensure proper mocking of external dependencies and use appropriate test setup (providers, wrappers) to avoid test environment issues. Tests should cover both happy path scenarios and error cases to maintain code reliability.
Ensure gRPC/RPC interfaces follow consistent patterns for return types, error handling, and method design. Avoid creating duplicate RPC methods when existing ones can be reused, use proper gRPC clients instead of direct imports, and maintain type safety with specific parameter types rather than generic objects.
Key principles:
Promise<Empty> not Promise<void>) to ensure compatibility across different platformsvalues: Record<string, any> objectsExample of proper gRPC handler:
// Good - proper return type and error handling
export async function addRemoteMcpServer(
controller: Controller,
request: AddRemoteMcpServerRequest
): Promise<McpServers> {
if (!request.serverName) {
throw new Error("Server name is required") // Native gRPC error
}
const servers = await controller.mcpHub?.addRemoteServer(request.serverName, request.serverUrl)
return { mcpServers: convertMcpServersToProtoMcpServers(servers) }
}
// Bad - generic response with custom error handling
interface CustomResponse {
success: boolean
error?: string
values?: Record<string, any>
}
This ensures API interfaces are predictable, type-safe, and work consistently across different client implementations.
Maintain consistent interface patterns across APIs and avoid loose coupling through magic strings or unstable properties. APIs should follow established conventions and provide stable, well-defined contracts.
Key principles:
Follow established patterns: When designing new APIs, align with existing SDK patterns and conventions. For example, subagent interfaces should “keep this interface consistent with what you see if you are using the SDKs natively” by using standard system prompt strings and chat pairs.
Avoid magic strings and loose metadata: Don’t rely on consumers knowing magic strings or loose information. Instead of metadata objects with string-based properties, use strongly-typed enums or explicit properties that provide compile-time safety.
Use stable properties: Prefer stable, well-defined properties over transient values. For instance, use schema (a stable BaseTool property) rather than parameterSchema (a transient value used to populate the schema field).
Standardize protocols: Extract common protocol patterns into shared libraries rather than having integrators hardcode protocol layers. Methods like ide/diffClosed should be part of a protocol library that IDE integrations can import.
Example of good API consistency:
// Good: Stable, consistent interface
interface ToolInterface {
name: string;
schema: SchemaUnion; // Stable property
execute(params: ToolParams): Promise<ToolResult>;
}
// Avoid: Loose coupling with magic strings
interface ToolInterface {
metadata: { source: string; behavior: string }; // Magic strings
parameterSchema: SchemaUnion; // Transient property
}
This approach ensures APIs are predictable, maintainable, and provide clear contracts for consumers.
Implement multiple types of resource constraints with appropriate thresholds to prevent performance degradation and resource exhaustion. This includes rate limiting, memory thresholds, execution time limits, and queue size bounds.
Key constraint types to implement:
Rate Limiting: Limit frequency of expensive operations
// Only record when RSS is 5%+ above previous high water mark
if (currentRss > previousHighWaterMark * 1.05) {
recordMemoryUsage(currentRss);
previousHighWaterMark = currentRss;
}
Time-based Constraints: Set reasonable timeouts to balance accuracy and user experience
// 50ms timeout for protocol detection to avoid blocking users
setTimeout(() => {
if (!checkFinished) {
detectionComplete = true;
resolve(false);
}
}, 50);
Execution Limits: Use multiple constraint types for long-running operations
interface RunConfig {
max_time_minutes: number;
max_turns: number; // Stop after N iterations
max_tokens: number; // Budget for resource consumption
}
Queue Size Bounds: Prevent unbounded growth with capacity limits
// Use FixedDeque with hard capacity limit
const events = new FixedDeque(1000);
const eventsToRetry = eventsToSend.slice(-this.max_retry_events); // Limit retry count
These constraints should be configurable and set based on the criticality of the operation - more lenient for user-facing features, stricter for background processes. Always consider the trade-off between resource protection and functionality degradation.
Ensure consistent naming patterns and approaches across similar functionality in the codebase. This includes using named constants instead of magic strings, aligning input handling patterns with existing code, maintaining consistent identifier formats, and following established conventions from libraries or existing implementations.
Key practices:
const CLEAR_QUEUE_SIGNAL = '__CLEAR_QUEUE__' instead of using the raw stringExample from the discussions:
// Before: Magic string
if (trimmedValue === '__CLEAR_QUEUE__') {
setQueuedInput(null);
return;
}
// After: Named constant
import { CLEAR_QUEUE_SIGNAL } from './constants.js';
if (trimmedValue === CLEAR_QUEUE_SIGNAL) {
setQueuedInput(null);
return;
}
This approach improves code maintainability, reduces errors from typos in magic strings, and makes the codebase more predictable for developers working across different modules.
When documenting configuration options, always specify exact file paths, explicit default values, and clarify potentially confusing settings to prevent user confusion. This includes documenting where settings are persisted, what happens when optional properties are omitted, and explaining any non-obvious behavior like token budget comparisons.
For example, instead of just mentioning “settings are saved,” specify the exact location:
// Settings are saved to ~/.gemini/settings.json
"vim": true
When documenting optional configuration properties, explicitly state the default behavior:
// authProviderType is optional - omitting it defaults to "dynamic_discovery"
"authProviderType": "dynamic_discovery" // default
For complex configurations that might cause confusion, add clarifying comments:
// tokenBudget is compared against character length as an approximation
"summarizeToolOutput": {
"run_shell_command": {
"tokenBudget": 100 // approximate token count, compared to character length
}
}
Avoid using the non-null assertion operator (!) and instead use union types or explicit null checks for better type safety. Non-null assertions bypass TypeScript’s null safety checks and can lead to runtime errors if the assumption is incorrect.
Preferred approach - Use union types:
// Instead of using non-null assertion
return {
filePath,
relativePathForDisplay,
fileReadResult: fileReadResult!.llmContent // ❌ Unsafe
};
// Use union types to make success cases explicit
type FileResult =
| { success: true; fileReadResult: FileReadResult }
| { success: false; reason: string };
// TypeScript now properly narrows the type
if (fileResult.success) {
// fileReadResult is guaranteed to exist here
return fileResult.fileReadResult.llmContent; // ✅ Safe
}
When explicit checks are safer:
// Instead of non-null assertion
return this.contentGenerator!; // ❌ Bypasses safety
// Use explicit null check with clear error handling
if (!this.contentGenerator) {
throw new Error('Content generator not initialized');
}
return this.contentGenerator; // ✅ Safe and clear
This approach makes null handling explicit in the type system and prevents runtime errors from incorrect assumptions about null values.
Before applying database migrations, systematically validate existing data and check for potential conflicts with current schema constraints. This prevents migration failures and ensures backward compatibility.
When modifying database schema or constants that affect database state:
Example approach for constraint modifications:
# 1. Select all, validate all names per user and update db
# 2. Create new table with constraint that does not conflict with existing constraint
# 3. Insert into it
# 4. Delete old table
This systematic validation prevents issues like foreign key conflicts during table recreation and ensures that changes to constants (like DEFAULT_FOLDER_NAME) don’t break existing database functions that depend on those values.
When configuring XML parsing options, carefully evaluate security implications of each setting, especially those that enable potentially risky features like DTD processing. Document the business justification for enabling such features and verify that the chosen library provides adequate protection against common XML-based attacks (XXE, DTD attacks, etc.).
Example of secure XML parsing configuration:
let doc = roxmltree::Document::parse_with_options(
xml_content,
roxmltree::ParsingOptions {
allow_dtd: true, // Enable only when necessary for business requirements
..Default::default()
},
)?;
Always include comments explaining why potentially dangerous options are enabled and confirm the library’s security guarantees against relevant attack vectors.
Always use optional chaining (?.) and nullish coalescing (??) operators when accessing potentially undefined or null properties. These patterns prevent TypeErrors when accessing nested properties and provide appropriate defaults only when values are null or undefined.
// Unsafe - may throw TypeError:
const message = runData.data[NodeConnectionTypes.Main][0][0].evaluationData;
const activeModules = [...settings.value.activeModules, 'data-store'];
const isMFAEnforced = settings.value.enterprise.mfaEnforcement;
// Safe - uses proper null handling:
const message = runData?.data?.[NodeConnectionTypes.Main]?.[0]?.[0]?.evaluationData ?? {};
const activeModules = [...(settings.value.activeModules ?? []), 'data-store'];
const isMFAEnforced = settings.value.enterprise?.mfaEnforcement ?? false;
When handling arrays from potentially empty sources, provide empty array defaults and filter out falsy values:
// Handle empty split results with proper filtering
const selectedApps = currentUserCloudInfo.value?.selectedApps?.split(',').filter(Boolean) ?? [];
// Check object existence before property access
if (toolOrToolkit && typeof (toolOrToolkit as Toolkit).getTools === 'function') {
// Now safe to call the method
}
// Use proper object access patterns to avoid null reference errors
const hasNodeRun = Object.prototype.hasOwnProperty.call(runData ?? {}, node.name);
Always ensure your type definitions accurately represent nullable values. If an API can return null for a field, include it in the type:
// Accurate type for a field that can be null
interface Response {
stop_reason: string | null;
}
Always use optional chaining and nullish coalescing operators to prevent runtime errors when accessing properties or methods on potentially undefined objects.
Key practices:
?.) when accessing properties that may be undefined:
// UNSAFE: May throw if connectionsByDestinationNode[name] is undefined
const activeNodeConnections =
workflowsStore.connectionsByDestinationNode[activeNode.value.name].main || [];
// SAFE: Uses optional chaining to prevent runtime errors
const activeNodeConnections =
workflowsStore.connectionsByDestinationNode[activeNode.value.name]?.main || [];
// UNSAFE: Only checks if node.value exists, but not if type exists
const packageName = computed(() => node.value?.type.split('.')[0] ?? '');
// SAFE: Checks both node.value and type before calling split
const packageName = computed(() => node.value?.type?.split('.')[0] ?? '');
?? (nullish coalescing) when you only want to provide a default for null or undefined|| (logical OR) when you want to provide a default for any falsy value (empty string, 0, false)
```typescript
// Only use a default when the value is null/undefined
return (props.inputDataLength ?? 1) > 1;// Use a default for any falsy value, including empty strings :placement=”tooltipPlacement || ‘right’” ```
// UNSAFE: Will throw if node.value.parameters is undefined
resource: node.value?.parameters.resource
// SAFE: Checks both node.value and parameters before accessing resource
resource: node.value?.parameters?.resource
This pattern makes your code more resilient by preventing the most common cause of runtime exceptions.
Ensure consistent terminology usage across the codebase, especially in localization files and technical documentation. When a term is established (whether in translation or technical context), maintain that same term throughout related files and contexts.
Key guidelines:
Example:
// Incorrect - Inconsistent terminology
{
"vectorStore": {
"embeddings": "埋め込み次元",
"dimensions": "ベクター次元" // Inconsistent with embeddings
}
}
// Correct - Consistent terminology
{
"vectorStore": {
"embeddings": "ベクター次元",
"dimensions": "ベクター次元" // Maintains consistency
}
}
This practice improves code maintainability, reduces confusion, and ensures a more professional user experience, especially in localized applications.
All user-facing features, APIs, and tools must have clear, comprehensive documentation that explains their purpose, limitations, and usage. Documentation should use terminology that users can understand, provide helpful guidance for common scenarios, and include warnings about potential issues.
Key requirements:
Example of good documentation:
/**
* Processes import statements in GEMINI.md content
* Supports @path/to/file.md syntax for importing content from other files
*
* Note: Only .md files are supported. Attempting to import other file types
* will result in a warning and the import will be skipped.
*/
export async function processImports(content: string, basePath: string): Promise<string> {
// Implementation with clear error messages for unsupported file types
if (!importPath.endsWith('.md')) {
console.warn(`[WARN] Only .md files are supported for imports. Skipping: ${importPath}`);
return content;
}
}
This ensures users can effectively use features without confusion and reduces support burden by providing clear guidance upfront.
Different types of errors require different handling strategies. Classify errors into categories and apply appropriate response patterns: fail fast for user-actionable problems, retry with backoff for transient issues, and graceful degradation for non-critical failures.
Error Classification Guidelines:
Example Implementation:
const shouldRetry = (err) => {
// Network errors - retry
if (!err.statusCode) return true;
// Rate limits and server errors - retry
if (err.statusCode === 429 || err.statusCode >= 500) return true;
// Client errors - fail fast
return false;
};
// For user-facing features - fail fast
if (userWantsTelemetry && !telemetryWorking) {
throw new Error('Telemetry failed - user should know');
}
// For background operations - graceful degradation
try {
await backgroundTelemetry();
} catch (error) {
console.debug('Background telemetry failed:', error);
// Continue execution
}
This approach prevents infinite retry loops on permanent failures while ensuring transient issues are handled gracefully and users are informed when they need to take action.
Avoid repeated computations and object creation in loops or high-frequency operations. Move invariant calculations outside the loop and reuse objects rather than creating new instances on each iteration. This reduces CPU overhead, memory churn, and improves performance in critical code paths.
Key practices:
Example - Before:
const searchByName = (query: string, limit: number = 20): NodeSearchResult[] => {
const normalizedQuery = query.toLowerCase();
const results: NodeSearchResult[] = [];
for (const nodeType of this.nodeTypes) {
// Name is lowercased on every iteration
if (nodeType.name.toLowerCase().includes(normalizedQuery)) {
// Score calculation logic...
}
}
// ...
};
After:
// Pre-calculate lowercase names when loading node types
const initNodeTypes = (types) => {
return types.map(type => ({
...type,
nameLower: type.name.toLowerCase(),
}));
};
const searchByName = (query: string, limit: number = 20): NodeSearchResult[] => {
const normalizedQuery = query.toLowerCase();
const results: NodeSearchResult[] = [];
for (const nodeType of this.nodeTypes) {
// Use pre-calculated lowercase name
if (nodeType.nameLower.includes(normalizedQuery)) {
// Score calculation logic...
}
}
// ...
};
Maintain consistent naming conventions throughout the codebase to improve readability and maintainability. This applies to translation keys, command names, variables, and terminology.
For translation keys:
dataStore.tab.label with data.store.empty.label or contextMenu.FilterExecutionsBy with references to contextMenu.filter_executions_byFor command and function names:
test:e2e or test:playwright instead of the ambiguous test:docker if the command runs playwright teststest:show:report instead of test:report to clarify the action being performedFor terminology:
Consistency in naming reduces cognitive load for developers, prevents bugs from mismatched references, and makes the codebase more maintainable over time.
When implementing algorithms, ensure they are both efficient and correct across all input cases. Key considerations:
Pattern matching edge cases: Ensure regex patterns handle all edge cases, including matches at the beginning of strings. For example, replace /[^\\][^\n]+/ with /(?:^ |
[^\])[^\n]+/ to catch backticks at string start. |
Algorithmic complexity: Prevent potential denial-of-service vulnerabilities by analyzing time complexity of algorithms, especially regular expressions on user input. For example, avoid patterns like /^\[([^\]]*)\]\s*(.*)$/ that can cause performance issues with certain inputs.
// Instead of:
for (let patternLength = 1; patternLength <= maxPatternLength; patternLength++) {
// Use:
for (let patternLength = 2; patternLength <= maxPatternLength; patternLength++) {
// Instead of:
return keywords.some((keyword) => text.includes(keyword))
// Use:
return keywords.some((keyword) => new RegExp(`\\b${keyword}\\b`).test(text))
Following these practices helps create algorithms that are not only computationally efficient but also robust against edge cases and potential security exploits.
Design APIs with explicit parameters rather than implicit defaults or hidden behavior. When an API function requires specific data or configuration, make those requirements clear through the function signature instead of relying on optional parameters with complex fallback logic.
This approach improves developer experience by making the API contract obvious and reducing confusion about what inputs are actually needed. Developers should be able to understand the API requirements without reading implementation details or documentation.
For example, instead of having optional parameters with hidden default resolution:
// Avoid: Hidden default behavior
async function routeEmail(email: Email, env: Env, options?: {
defaultAgentName?: string;
defaultAgentId?: string;
}) {
// Complex internal logic to determine routing
}
// Prefer: Explicit resolver requirement
async function routeEmail(
email: Email,
env: Env,
resolver: EmailResolver<Env> // Required, not optional
) {
// Clear contract - resolver is always needed
}
Similarly, extract and pass only the specific data needed rather than entire objects:
// Instead of passing entire request object
const error = await doStub.onSSEMcpMessage(sessionId, request);
// Extract and pass only what's needed
const messageBody = await request.json();
const error = await doStub.onSSEMcpMessage(sessionId, messageBody);
This principle applies to method parameters, configuration options, and data extraction - always favor explicit, clear interfaces over implicit behavior that requires developers to understand internal implementation details.
Always access and set configuration values using established patterns and correct property names. Understanding the structure of configuration objects is essential to prevent bugs in your application.
When working with external services:
underlyingProviderName instead of provider for services behind proxies)When handling persistent configurations:
When setting conditional configuration values:
// Incorrect
if (defaultModel?.provider === "anthropic") { ... }
const storedId = localStorage.getItem("lastSessionId");
const alwaysApply = newRuleType !== RuleType.AgentRequested;
// Correct
if (defaultModel?.underlyingProviderName === "anthropic") { ... }
const storedId = getLocalStorage("lastSessionId");
const alwaysApply = newRuleType === RuleType.Always || newRuleType === RuleType.AutoAttached;
When building React components that handle rapid user input or manage complex interdependent state, consolidate state management to prevent race conditions that occur when multiple events are processed in the same React event loop.
Key strategies:
Use useReducer for complex interdependent state instead of multiple useState calls. This centralizes state logic, improves performance by reducing re-renders, and eliminates potential race conditions from multiple state updates.
Integrate utility functions with centralized state rather than operating on potentially stale closures or separate state variables.
Example:
// ❌ Problematic: Multiple useState calls for interdependent state
const [mode, setMode] = useState('NORMAL');
const [count, setCount] = useState(0);
const [pendingG, setPendingG] = useState(false);
const [pendingD, setPendingD] = useState(false);
// ❌ Utility functions operating separately
const findNextWordStart = (text: string, offset: number) => {
// May operate on stale state when multiple keystrokes occur rapidly
};
// ✅ Better: Single useReducer for interdependent state
const [state, dispatch] = useReducer(vimReducer, {
mode: 'NORMAL',
count: 0,
pendingG: false,
pendingD: false,
});
// ✅ Integrate utilities with centralized state management
// Move utility functions into the same state management system
// to ensure they operate on current state
This approach prevents issues where “multiple keystrokes need to be processed in the same React event loop” and eliminates race conditions from managing complex state machines in React components.
Prefer Rust’s built-in optional handling methods over manual checks and intermediate variables. Use if let Some(value) = option for pattern matching, option.map(|x| x.field).unwrap_or(default) for transformations with fallbacks, and option.is_some_and(|x| condition) for conditional checks.
Instead of creating intermediate variables:
let is_recipe_execution = recipe.is_some();
let recipe_name_for_telemetry = recipe.clone().unwrap_or_default();
Use direct pattern matching:
if let Some(recipe_name) = recipe {
// use recipe_name directly
}
Instead of verbose match statements:
let recipe_version = match load_recipe(&name, params) {
Ok(recipe) => recipe.version,
Err(_) => "unknown".to_string(),
};
Use method chaining:
let recipe_version = load_recipe(&name, params)
.map(|r| r.version)
.unwrap_or_else(|| "unknown".to_string());
These patterns reduce boilerplate, improve readability, and leverage Rust’s type system for safer null handling.
Implement comprehensive error handling that covers prevention, recovery, and diagnosis:
// Instead of just checking mime type and filename
function isDownloadable(index, key) {
const { mimeType, fileName } = binaryData[index][key];
return !!(mimeType && fileName && (binaryData[index][key].id || binaryData[index][key].data));
}
try {
cancellingTestRun.value = true;
await evaluationStore.cancelTestRun(workflowId, runId);
} catch (error) {
// Error handling
} finally {
cancellingTestRun.value = false;
}
} catch (error) {
console.error(chalk.red(`An error occurred during the build process: ${error}`));
}
Each layer of error handling contributes to a more robust application that prevents user frustration and simplifies troubleshooting.
Avoid useRef unless strictly necessary and ensure useEffect has proper dependencies to prevent unnecessary re-renders. useRef makes logic harder to reason about and should be replaced with more straightforward patterns when possible. For useEffect, extract values outside the effect when they don’t need to be dependencies, and ensure the dependency array accurately reflects what the effect actually uses.
Example of avoiding useRef:
// Instead of using useRef for callbacks
() => toggleVimModeRef.current?.()
// Use a generic function approach
const handleSettingsUpdate = (updateFn) => updateFn();
Example of optimizing useEffect:
// Extract values that don't need to be dependencies
const prompt = config.getQuestion();
useEffect(() => {
// Use prompt here
}, [/* proper dependencies only */]);
This approach improves code maintainability by making component logic more predictable and reducing unnecessary re-renders that can impact performance.
When designing APIs, favor lightweight, composable solutions that allow callers to maintain control over their specific use cases, rather than imposing centralized, monolithic systems that take control away from the caller.
This principle emerges from recognizing that different parts of an application often have unique requirements that are difficult to accommodate in a one-size-fits-all solution. Lightweight APIs that provide building blocks for callers to compose are more flexible and easier to adopt incrementally.
For example, instead of creating a centralized service that “requires taking control of all useInput in the application,” design an API that “allows callers to resolve whether specific input matches a specific keybinding.” This approach respects existing code patterns and reduces the risk of breaking changes during adoption.
Similarly, when handling user input or arguments, prefer simple, predictable approaches like direct appending rather than complex parsing mechanisms with special separators. This makes the API more intuitive and reduces cognitive overhead for both implementers and users.
// Avoid: Centralized control that requires major refactoring
const keybindingService = new KeybindingService();
keybindingService.takeControlOfAllInput();
// Prefer: Composable utilities that work with existing patterns
const isMatch = keybindingResolver.matches(input, 'save-file');
if (isMatch) handleSave();
Ensure that all text strings in locale-specific files are properly translated into their respective languages. Leaving untranslated English text in non-English locale files creates an inconsistent user experience and reduces the effectiveness of localization efforts.
When adding new features or UI elements:
Example of a problem:
// webview-ui/src/i18n/locales/es/mcp.json
{
"serverStatus": {
"retrying": "Reintentando...",
"retryConnection": "Reintentar conexión",
"disabled": "Server is disabled" // English text in Spanish file
}
}
Correct implementation:
// webview-ui/src/i18n/locales/es/mcp.json
{
"serverStatus": {
"retrying": "Reintentando...",
"retryConnection": "Reintentar conexión",
"disabled": "Servidor deshabilitado" // Properly translated to Spanish
}
}
All user-facing text must be wrapped with translation functions instead of using hardcoded English strings. This includes regular UI text, accessibility attributes (aria-label, title, alt), and screen reader announcements. Using translation keys creates a consistent, maintainable internationalization system and ensures the application is accessible to users in all supported languages.
When using translation functions:
// Incorrect
<h2 className="text-lg font-bold">Something went wrong</h2>
<button title="Add reaction" aria-label="Collapse command management section">
{screenReaderAnnouncement}
</button>
// Correct
<h2 className="text-lg font-bold">{t("errorBoundary.title")}</h2>
<button
title={t("emojiReactions.add")}
aria-label={t("chat:commandExecution.collapseManagement")}>
{t("chat:screenReader.announcement")}
</button>
For string interpolation, use translation parameters rather than concatenating strings:
// Incorrect
<span>{`File: ${selectedOption.value}, ${selectedMenuIndex + 1} of ${options.length}`}</span>
// Correct
<span>
{t("chat:contextMenu.announceFile", {
name: selectedOption.value,
position: t("chat:contextMenu.position", {
current: selectedMenuIndex + 1,
total: options.length
})
})}
</span>
Prefer centralized configuration objects over environment variables for application settings. Environment variables create inconsistent configuration sources and can lead to maintenance challenges.
Guidelines:
Config structure as the “one true way” to configure your applicationFor feature flags or experimental options, use structured configuration with appropriate prefixes:
// Preferred
config.experimental_resume = true;
// Instead of
if std::env::var("CODEX_EXPERIMENTAL_RESUME").is_ok() { ... }
When environment variables must be used:
Remember that modifying environment variables is inherently racy in multi-threaded contexts and has been marked as unsafe in recent Rust editions.
Select data structures and algorithms that match your performance requirements rather than defaulting to simple but inefficient approaches. Consider the time complexity of operations and use specialized libraries when appropriate.
Key principles:
Example from the discussions:
// Avoid: O(n) splice operations on arrays
if (this.events.length >= this.max_events) {
const eventsToRemove = this.events.length - this.max_events + 1;
this.events.splice(0, eventsToRemove); // O(n) operation
}
// Prefer: O(1) operations with appropriate data structure
import { FixedDeque } from 'mnemonist';
// FixedDeque automatically handles overflow with O(1) operations
this.events = new FixedDeque(this.max_events);
this.events.push(newEvent); // O(1) with automatic FIFO overflow
Similarly, prefer glob libraries over recursive directory traversal, and minimatch over custom regex implementations for pattern matching. The performance benefits compound significantly as data sizes grow.
Always validate API request and response data using schema validation to ensure type safety and prevent runtime errors. Define explicit schemas (e.g., using Zod or similar) for all API interfaces rather than relying on TypeScript types alone.
Example:
// Before
interface ChatMessage {
action: string;
chatInput: string;
sessionId: string;
}
async function handleMessage(data: RawData) {
const message = jsonParse<ChatMessage>(data.toString());
// No validation, could fail at runtime
await processMessage(message);
}
// After
const chatMessageSchema = z.object({
action: z.enum(['user', 'system']),
chatInput: z.string(),
sessionId: z.string().uuid()
});
type ChatMessage = z.infer<typeof chatMessageSchema>;
async function handleMessage(data: RawData) {
const rawMessage = jsonParse(data.toString());
const message = chatMessageSchema.parse(rawMessage);
// Validated data, guaranteed to match schema
await processMessage(message);
}
This practice:
When writing concurrent code, minimize blocking operations to maintain responsiveness and prevent performance bottlenecks. This applies especially to async contexts and lock usage.
For asynchronous operations:
tokio::spawn over thread creation for concurrent tasks, as it’s more lightweightFor lock handling:
Example - Before:
{
let mut running_requests_id_to_codex_uuid = running_requests_id_to_codex_uuid.lock().await;
running_requests_id_to_codex_uuid.insert(request_id.clone(), session_id);
}
After:
running_requests_id_to_codex_uuid.lock().await.insert(request_id.clone(), session_id);
For mutex usage:
// Bad: Lock held longer than necessary
let mut flag = self.pending_redraw.lock().unwrap();
if *flag {
return;
}
*flag = true;
// Lock still held here when it's no longer needed
// Good: Lock released as soon as possible
{
let mut flag = self.pending_redraw.lock().unwrap();
if *flag {
return;
}
*flag = true;
} // Lock released here
// Continue with operations that don't need the lock
Structure code files with a clear top-down organization, placing primary functions and important declarations at the top, followed by helper functions and implementation details below. This improves code readability and maintainability by establishing a clear hierarchy.
Key principles:
Example:
// Primary public interface first
pub fn process_event(&mut self, event: Event) {
self.dispatch_event(event)
}
// Main implementation functions next
fn dispatch_event(&mut self, event: Event) {
let common_data = self.prepare_common_data(); // Shared computation moved up
match event {
Event::A => self.handle_a(common_data),
Event::B => self.handle_b(common_data),
}
}
// Helper functions last
fn prepare_common_data(&self) -> Data {
// Implementation details...
}
fn handle_a(&mut self, data: Data) {
// Implementation details...
}
fn handle_b(&mut self, data: Data) {
// Implementation details...
}
Always protect sensitive credential data through proper encryption, secure storage, and careful handling in code. Key requirements:
Example - Instead of:
class Config {
password: string = 'admin'; // BAD: Hardcoded credential
constructor(options) {
this.tls = {}; // BAD: Overwrites user TLS settings
}
}
Use:
class Config {
@Env('DB_PASSWORD') // GOOD: Environment variable
password: string = '';
constructor(options) {
this.tls = options.tls ?? {}; // GOOD: Preserves settings
}
}
// GOOD: Proper credential field protection
class Credentials {
@Column({
type: 'string',
typeOptions: { password: true } // Enables encryption
})
sslKey: string;
}
---
## Prevent unnecessary processing
<!-- source: RooCodeInc/Roo-Code | topic: Performance Optimization | language: TSX | updated: 2025-07-22 -->
Optimize React component performance by minimizing unnecessary operations that can slow down your application:
1. **Memoize stable components** to prevent unnecessary re-renders when parent components update:
```typescript
// Instead of using components directly
<DeleteMessageDialog {...props} />
// Memoize components that receive the same props frequently
const MemoizedDeleteMessageDialog = React.memo(DeleteMessageDialog);
<MemoizedDeleteMessageDialog {...props} />
const timeoutId = setTimeout(() => { // Perform the operation after a brief delay }, 100);
return () => clearTimeout(timeoutId); }, [frequentlyChangingDependency]);
3. **Avoid inefficient deep comparisons** on large objects:
```typescript
// Avoid this pattern on large objects
if (JSON.stringify(objA) !== JSON.stringify(objB)) {
// Update logic
}
// Instead, use dedicated comparison libraries or memoized selectors
import { isEqual } from 'lodash';
if (!isEqual(objA, objB)) {
// Update logic
}
); }
// Create providers once at a higher level:
function App() {
return (
These optimizations should be applied thoughtfully where measurements show actual performance impact, rather than as premature optimization.
---
## Avoid unnecessary operations
<!-- source: openai/codex | topic: Performance Optimization | language: Rust | updated: 2025-07-22 -->
Optimize performance by eliminating operations that don't contribute meaningful value to your code's functionality. Look for three common performance drains:
1. **Redundant I/O operations**: Avoid unnecessary file system operations like flushing a file that has already been flushed or has no new content.
2. **Excessive UI rendering**: Implement throttling at the appropriate architectural level rather than in individual components. Consider centralizing performance controls in higher-level components where they can be applied globally.
3. **Unnecessary memory allocations**: Use references or smarter allocation patterns instead of blindly cloning data structures.
```rust
// Instead of always cloning:
let prompt = if missing_calls.is_empty() {
prompt.clone()
// ...
}
// Use Cow to avoid unnecessary cloning:
let prompt: Cow<'_, Prompt> = if missing_calls.is_empty() {
Cow::Borrowed(prompt)
} else {
// Only clone when necessary
Cow::Owned(prompt.clone().with_additional_items(missing_calls))
}
Each unnecessary operation compounds to create performance bottlenecks. Regularly review your code for these patterns and refactor when identified.
Identify and eliminate code duplication by extracting shared logic into reusable functions, components, or type definitions. When you notice similar code patterns appearing in multiple places, refactor them into a single, well-named abstraction.
This applies to:
For example, instead of duplicating JSX:
{extensionTooltip ? (
<TooltipWrapper tooltipContent={extensionTooltip}>
<span className="ml-[10px]">
{getToolDescription() || snakeToTitleCase(toolCall.name)}
</span>
</TooltipWrapper>
) : (
<span className="ml-[10px]">
{getToolDescription() || snakeToTitleCase(toolCall.name)}
</span>
)}
Extract the shared element:
const toolLabel = (
<span className="ml-[10px]">
{getToolDescription() || snakeToTitleCase(toolCall.name)}
</span>
);
return extensionTooltip ? (
<TooltipWrapper tooltipContent={extensionTooltip}>{toolLabel}</TooltipWrapper>
) : (
toolLabel
);
Similarly, extract repeated function calls:
// Instead of repeating setMentionPopover(prev => ({ ...prev, isOpen: false }))
const closeMentionPopover = () => {
setMentionPopover(prev => ({ ...prev, isOpen: false }));
};
This improves maintainability, reduces the chance of inconsistencies, and makes the code more readable by giving meaningful names to repeated patterns.
Don’t automatically reach for useMemo and useCallback for every computation or function. These hooks add complexity and should only be used when there’s a measurable performance benefit. Consider the actual cost of the operation and frequency of re-renders before memoizing.
Use memoization when:
Avoid memoization for:
Example of appropriate memoization:
// Good: Component re-renders frequently, URL construction has dependencies
const clineUris = useMemo(() => {
const base = new URL(clineUser?.appBaseUrl || CLINE_APP_URL)
const dashboard = new URL("dashboard", base)
const credits = new URL(activeOrganization ? "/organization" : "/account", dashboard)
credits.searchParams.set("tab", "credits")
return { dashboard, credits }
}, [clineUser?.appBaseUrl, activeOrganization])
Remember: “Premature optimization is the root of all evil.” Profile first, optimize second.
Use console.debug() for debug information instead of console.log() to prevent cluttering user-facing output. Debug information should be hidden from normal users but available when debugging is enabled.
When logging information that is primarily useful for developers or troubleshooting, use console.debug() rather than console.log(). This ensures that users don’t see unnecessary technical details during normal operation, while still making the information available when needed for debugging.
Example:
// Bad - users will see this debug information
console.log("buildImangeName:imageName ", imageName);
console.log(`Discovered tool: ${funcDecl.name}`);
// Good - debug information is properly categorized
console.debug("buildImangeName:imageName ", imageName);
console.debug(`Discovered tool: ${funcDecl.name}`);
This practice improves user experience by keeping the console output clean while maintaining valuable debugging capabilities for developers.
When choosing names for variables, methods, classes, or configuration sections, consider both the current purpose and potential future extensions. Names should be semantically accurate and align with established conventions in the codebase.
For configuration sections or groupings, choose names that can accommodate related functionality rather than being overly specific. For example, prefer “triggers” over “keybindings” if the section might later include other trigger types like diagnostics or watch triggers.
Always verify that naming choices follow existing team conventions and documented rules. Consistency with established patterns is crucial for maintainability.
Example:
// Instead of overly specific:
"keybindings": { ... }
// Choose semantically broader:
"triggers": {
"keybindings": { ... },
// Future: "diagnostics": { ... }
}
When implementing security-related configuration options, use generic, implementation-agnostic naming conventions rather than tying them to specific tools or runtimes. This approach ensures flexibility as the underlying technology stack evolves and prevents vendor lock-in in security configurations.
For example, when adding container security flags, prefer generic names like SANDBOX_FLAGS over tool-specific names like DOCKER_RUN_FLAGS. This allows the same configuration to work across different container runtimes (Docker, Podman, etc.) without requiring changes to user configurations.
Example:
# Good: Generic naming that works across container runtimes
export SANDBOX_FLAGS="--security-opt label=disable"
# Avoid: Tool-specific naming that limits flexibility
export DOCKER_RUN_FLAGS="--security-opt label=disable"
This principle is especially important for security configurations because:
When reviewing security-related configuration code, ensure that environment variables, configuration keys, and API parameters use descriptive, generic names that reflect their security purpose rather than the specific tool being configured.
Ensure thread-safe access to shared state by using appropriate synchronization mechanisms and atomic operations. Avoid race conditions by:
Example of unsafe code:
class StateManager {
private cachedInfo: ModelInfo | null = null;
async getInfo() {
if (!this.cachedInfo) { // Race condition: multiple threads might pass this check
this.cachedInfo = await fetchModelInfo(); // Multiple simultaneous fetches possible
}
return this.cachedInfo;
}
}
Safe version:
class StateManager {
private cachedInfo: ModelInfo | null = null;
private fetchPromise: Promise<ModelInfo> | null = null;
async getInfo() {
if (this.fetchPromise) {
return this.fetchPromise; // Reuse in-flight request
}
if (!this.cachedInfo) {
this.fetchPromise = fetchModelInfo();
try {
this.cachedInfo = await this.fetchPromise;
} finally {
this.fetchPromise = null; // Clear promise reference
}
}
return this.cachedInfo;
}
}
This pattern prevents multiple simultaneous fetches, handles errors gracefully, and maintains state consistency across async operations.
Extract repetitive or complex code into reusable functions, components, or custom hooks. This improves code organization, reduces duplication, and enhances readability.
For UI components:
For logic patterns:
Example (Before):
// Complex event handling logic embedded in component
const className = primaryButtonText === t("chat:startNewTask.title") && currentTaskItem?.id
? "flex-1 mr-[6px]"
: secondaryButtonText
? "flex-1 mr-[6px]"
: "flex-[2] mr-0";
// Repeated pattern for extracting values from events
const value = (e as unknown as CustomEvent)?.detail?.target?.value ||
((e as any).target as HTMLTextAreaElement).value;
Example (After):
// Helper function for className logic
function getButtonClassName(primaryButtonText, t, currentTaskItem, secondaryButtonText) {
const showShareButton = primaryButtonText === t("chat:startNewTask.title") && currentTaskItem?.id;
return showShareButton || secondaryButtonText
? "flex-1 mr-[6px]"
: "flex-[2] mr-0";
}
// Reusable event value extractor
function getEventValue(e: React.SyntheticEvent | CustomEvent): string {
return (e as unknown as CustomEvent)?.detail?.target?.value ||
((e as React.ChangeEvent<HTMLTextAreaElement>).target).value;
}
Always validate configuration values before use, provide sensible defaults, and centralize constants in shared modules. When implementing configuration handling:
// Correct: Properly handles zero values if (configuration.commandExecutionTimeout !== undefined) { // Handle timeout }
2. Apply bounds checking for numerical values to ensure they're within acceptable ranges:
```typescript
// Validate within reasonable bounds
const maxImagesPerResponse = Math.max(1, Math.min(100, state?.mcpMaxImagesPerResponse ?? 20));
const maxImageSizeMB = Math.max(0.1, Math.min(50, state?.mcpMaxImageSizeMB ?? 10));
// Ensure configuration value is a valid number
this.modelDimension = typeof config.modelDimension === 'number' && !isNaN(config.modelDimension)
? config.modelDimension
: DEFAULT_MODEL_DIMENSION;
// Use the constant throughout the codebase return settings.claudeCodeMaxOutputTokens || DEFAULT_CLAUDE_CODE_MAX_OUTPUT_TOKENS;
Proper configuration handling prevents subtle bugs, improves maintainability, and makes your code more resilient to external changes.
---
## Document i18n string usage
<!-- source: RooCodeInc/Roo-Code | topic: Documentation | language: TypeScript | updated: 2025-07-21 -->
All user-facing strings must be documented with translation function usage to ensure proper internationalization support. This includes error messages, notifications, labels, and any text displayed to users.
Example:
```typescript
// ❌ Don't use hardcoded user-facing strings
const notice = `Image file is too large (${imageSizeInMB} MB). The maximum allowed size is 5 MB.`
// ✅ Document translation key usage for user-facing strings
const notice = t('tools:readFile.imageTooLarge', {
size: imageSizeInMB,
max: 5
})
Key requirements:
This ensures maintainable internationalization support and clear documentation of translatable content throughout the codebase.
Remove or conditionally disable console.log and console.debug statements before committing code to production. These debugging statements create noise in browser consoles, may expose sensitive information, and can impact runtime performance.
Instead of using direct console logging statements, implement a logging utility that respects environment settings:
// logger.ts
export const logger = {
debug: (message: string, ...args: any[]) => {
if (process.env.NODE_ENV === 'development' || localStorage.getItem('debug-enabled') === 'true') {
console.debug(`[DEBUG] ${message}`, ...args);
}
},
log: (message: string, ...args: any[]) => {
if (process.env.NODE_ENV === 'development' || localStorage.getItem('debug-enabled') === 'true') {
console.log(`[LOG] ${message}`, ...args);
}
},
// Always show warnings and errors
warn: (message: string, ...args: any[]) => console.warn(`[WARN] ${message}`, ...args),
error: (message: string, ...args: any[]) => console.error(`[ERROR] ${message}`, ...args),
};
// Usage example - replaces instances like:
// console.log(`McpErrorRow level: ${error.level} for message: ${error.message.substring(0, 20)}...`)
// With:
logger.debug(`McpErrorRow level: ${error.level} for message: ${error.message.substring(0, 20)}...`);
For test files, remove all debugging statements entirely to keep test output clean. Consider adding a linting rule to catch accidental console statements before they reach code review.
Apply these React optimization techniques to improve component performance and maintainability:
{/* Avoid this */}
{patterns.map((item, index) => (
<div key={`${item.pattern}-${index}`} className="ml-5 flex items-center gap-2">
{/* content */}
</div>
))}
{/* Prefer this */}
{patterns.map((item) => (
<div key={item.pattern} className="ml-5 flex items-center gap-2">
{/* content */}
</div>
))}
// Avoid recreating arrays/objects on every render
const toolGroups = React.useMemo(() => [
// array contents
], [/* dependencies */]);
// Instead of:
const enhanceButton = document.querySelector('[aria-label*="enhance"]');
// Prefer:
const enhanceButtonRef = useRef(null);
// Then pass the ref to the component
<Button ref={enhanceButtonRef} aria-label="enhance" />
// Instead of tracking all instances in a collection:
const [followUpAnswered, setFollowUpAnswered] = useState<Set<number>>(new Set());
// Consider tracking just what's needed:
const [currentFollowUpTs, setCurrentFollowUpTs] = useState<number | null>(null);
When dealing with values that may be null or undefined, explicitly leverage TypeScript’s nullable types to identify dependencies and guide null handling decisions. Make values nullable when their availability is uncertain, then let TypeScript reveal where null checks are needed.
For runtime scenarios where the type system cannot guarantee non-null values (like providers or external dependencies), use defensive null checks with optional chaining:
// When type system can't guarantee non-null at runtime
if (chatContext?.setRecipeParameters) {
chatContext.setRecipeParameters(inputValues);
}
For values you control, make them explicitly nullable and let TypeScript guide you to handle all null cases:
// Make uncertain values explicitly nullable
let pid: number | null;
// TypeScript will now enforce null checks wherever pid is used
This approach combines the safety of explicit nullable types with defensive programming for runtime uncertainties, ensuring comprehensive null handling coverage.
Always consider the computational complexity of your algorithms and leverage efficient built-in methods when available. Look for opportunities to reduce time complexity and avoid unnecessary operations like redundant loops or object creation.
Common inefficiencies to watch for:
Examples of improvements:
Before (O(n^2) deduplication):
promptParams.forEach((promptParam) => {
if (!allParams.some((param) => param.key === promptParam.key)) {
allParams.push(promptParam);
}
});
After (O(n) with Map):
const paramMap = new Map(allParams.map(p => [p.key, p]));
promptParams.forEach(p => paramMap.set(p.key, p));
const allParams = Array.from(paramMap.values());
Before (unnecessary string creation):
const beforeCursor = text.slice(0, cursorPosition);
const lastAtIndex = beforeCursor.lastIndexOf('@');
After (direct method usage):
const lastAtIndex = text.lastIndexOf('@', cursorPosition - 1);
Always verify that objects and their properties exist before accessing them to prevent null reference errors. This includes checking for undefined global objects, optional parameters, and nested properties.
When you know an object or property is guaranteed to exist (like when checking param.default exists), keep the logic simple and avoid unnecessary validation:
// Good: Simple check when we know default exists
if (param.requirement === 'optional' && param.default) {
initialValues[param.key] = param.default;
}
When accessing potentially undefined objects, add explicit checks:
// Good: Check object existence before use
useEffect(() => {
if (window.electron) {
const currentVersion = window.electron.getVersion();
setUpdateInfo((prev) => ({ ...prev, currentVersion }));
}
}, []);
This prevents runtime errors and makes your code more robust by handling null/undefined cases explicitly rather than assuming objects will always be available.
Always handle potentially null or undefined values explicitly using type guards, null coalescing operators, and proper fallback values. This ensures type safety and prevents runtime errors from null references.
Key practices:
// Good
const reservedTokens = maxTokens ?? DEFAULT_TOKENS
// Bad - will override 0 with default
const reservedTokens = maxTokens || DEFAULT_TOKENS
// Good
if (typeof data === "object" && data !== null && "property" in data) {
return data.property
}
// Bad
return data?.property || defaultValue
// Good
const description = mode.description ?? mode.whenToUse ?? mode.roleDefinition ?? ''
// Bad
const description = mode.description || mode.whenToUse || mode.roleDefinition
This approach prevents subtle bugs from implicit type coercion and makes null handling intentions clear in the code.
Use consistent naming patterns throughout the codebase. When adding new identifiers, follow existing patterns in similar contexts. This includes:
Example of inconsistent naming:
// Inconsistent - mixing patterns
alwaysAllowReadOnly: true,
alwaysAllowWrite: true,
alwaysApproveResubmit: true, // Should be alwaysAllowResubmit
// Inconsistent casing
const getLmStudioModels = ...
const getLMStudioModels = ... // Inconsistent LM vs LM
// Inconsistent constant naming pattern
const SEARCH_MIN_SCORE = 0.4
const DEFAULT_MAX_SEARCH_RESULTS = 50 // Pattern mismatch
Corrected version:
// Consistent prefix pattern
alwaysAllowReadOnly: true,
alwaysAllowWrite: true,
alwaysAllowResubmit: true, // Follows established pattern
// Consistent casing
const getLMStudioModels = ... // Standardized on LM
const getLMStudioModels = ...
// Consistent constant naming pattern
const DEFAULT_SEARCH_MIN_SCORE = 0.4
const DEFAULT_MAX_SEARCH_RESULTS = 50 // Consistent pattern
When adding new identifiers:
Documentation should explain what isn’t obvious from the code itself. Focus on providing context about “why” certain decisions were made rather than restating what the code does.
Key practices:
Good example:
// Number of terminal rows consumed by the textarea border (top + bottom).
const TEXTAREA_BORDER_LINES: u16 = 2;
Not as useful:
// Render the main paragraph
paragraph.render_ref(area, buf);
When writing tests, include docstrings that explain what behavior is being verified, especially when the test involves complex setup code. For public functions, ensure return values are documented when their meaning isn’t immediately clear from the function name or signature.
Always validate and sanitize user-provided inputs before using them in security-sensitive operations to prevent XSS attacks and unsafe redirections.
When handling URLs from user input:
When inserting content into the DOM:
Example (improved URL validation):
function loadUrl(url) {
try {
// Parse and validate URL
const urlObj = new URL(url, window.location.origin);
// Only allow http and https protocols
if (urlObj.protocol !== 'http:' && urlObj.protocol !== 'https:') {
console.error('Invalid URL protocol');
return;
}
// Use the validated URL
iframe.src = urlObj.toString();
} catch (e) {
console.error('Invalid URL format', e);
}
}
This practice helps prevent client-side open redirect vulnerabilities and cross-site scripting (XSS) attacks that could compromise user security.
Always propagate errors with appropriate context rather than silently ignoring them. This makes debugging easier and prevents unexpected behavior.
Do:
anyhow.context() or .with_context() to explain what operation failedDon’t:
.expect() or .unwrap() in production codeExample - Bad:
// Silently ignoring errors
parser.set_language(&lang).expect("load bash grammar");
// Ignoring I/O errors
async fn rollout_writer(...) {
if let Some(meta) = meta {
// I/O errors ignored here
}
}
Example - Good:
// Adding context to errors
parser
.set_language(&lang)
.context("failed to load bash grammar")?;
// Properly handling utf8 conversion errors
let text = node
.utf8_text(bytes)
.map_err(|e| anyhow::anyhow!("failed to interpret heredoc body as UTF-8: {e}"))?;
// Properly propagating I/O errors
async fn rollout_writer(...) -> std::io::Result<()> {
if let Some(meta) = meta {
// Return I/O errors
}
Ok(())
}
Critical system dependencies failing should cause immediate failure rather than silent recovery. For common error patterns, consider creating utility functions that handle errors consistently.
Maintain consistent terminology when describing AI systems, capabilities, and workflows throughout documentation and content. This includes using standardized terms for AI entities (consistently choosing between “AI”, “assistant”, “model”, or “agent”), technical processes, and capability descriptions.
Key areas to standardize:
Example of inconsistent terminology:
The AI can help with data analysis. The model explores data through execution.
The assistant understands and builds upon existing state.
Example of consistent terminology:
The assistant can help with data analysis. The assistant explores data through execution.
The assistant understands and builds upon existing state.
This consistency helps readers better understand AI system capabilities and creates more professional, trustworthy documentation. It’s particularly important when describing AI workflows, limitations, and collaborative processes between humans and AI systems.
Always verify configuration values against official documentation and test across target platforms before committing. Invalid configuration values can cause build failures, runtime errors, or platform-specific issues that are difficult to debug.
Key validation practices:
Example of problematic configuration:
// tsconfig.json - Invalid lib value
{
"compilerOptions": {
"lib": ["es2022", "esnext.disposable", "DOM"] // ❌ "esnext.disposable" is not valid
}
}
// Fixed version
{
"compilerOptions": {
"lib": ["es2022", "DOM"] // ✅ Valid lib values only
}
}
This prevents configuration-related build failures and ensures consistent behavior across development environments.
Before implementing new functionality, check if similar utilities or patterns already exist in the codebase. Consolidate duplicate logic and leverage existing libraries to maintain consistency and reduce maintenance overhead.
Key practices:
ansi.Strip instead of implementing util.StripAnsi)ctrl+p to existing Up binding instead of creating separate CtrlP binding)Example:
// Instead of creating new utility
out := util.StripAnsi(fmt.Sprintf("%s", stdout))
// Reuse existing library
out := ansi.Strip(fmt.Sprintf("%s", stdout))
This approach improves code maintainability, reduces duplication, and ensures consistent patterns across the codebase.
Properly configure development tools to maintain consistent code formatting across the entire codebase and development environments. This includes setting up formatter ignore files, git attributes, and other configuration files that ensure uniform code style regardless of developer setup or platform differences.
Key areas to configure:
.prettierignore or similar files to exclude generated directories, build outputs, and third-party code from formatting.gitattributes with * text=auto eol=lf to prevent platform-specific line ending issuesout/, build/, dist/ from formatting toolsExample configuration:
# .prettierignore
evals/
docs/
out/
# .gitattributes
* text=auto eol=lf
This approach prevents formatting inconsistencies that can cause unnecessary diff noise and ensures all team members work with the same code style standards, regardless of their local development environment.
Maintain clean and consistent code by removing unnecessary elements and following standard practices:
// Bad
import { computed, watch } from 'vue'; // watch is never used
// Good
import { computed } from 'vue';
// Bad
// const { getReportingURL } = useBugReporting();
// <LogoText v-if="showLogoText" :class="$style.logoText" />
// Good
// Import only what's needed, remove completely when no longer used
/* Bad */
.container {
justify-content: right; /* Invalid value */
}
<style v-if="content.css" type="text/css" scoped> /* Non-standard usage */
/* Good */
.container {
justify-content: flex-end; /* Standard value */
}
/* Bad - selector with no matching elements */
.titleInput input {
/* styles that will never be applied */
}
// Bad
// eslint-disable-next-line @typescript-eslint/return-await
return await somePromise();
// Good
return somePromise(); // Fix the underlying issue instead
Following these practices improves code readability, reduces maintenance overhead, and prevents subtle bugs from entering your codebase.
When integrating with AI models and LLMs, structure your code to properly handle model responses, separate concerns between layers, and implement robust failure detection mechanisms.
Core Principles:
Separate raw model data from presentation logic: Core libraries should emit raw model responses (like finish reasons, confidence scores) while UI layers handle user-facing formatting and messages. This ensures library consumers aren’t forced to receive UI-specific content.
Design schemas with proper field ordering: When using structured generation with AI models, place reasoning fields before conclusion fields in your schema. This encourages the model to think through the problem before providing final answers, improving response quality.
Implement systematic failure detection: For long-running AI interactions, implement detection mechanisms for common failure modes like repetitive loops or unproductive states. Use dynamic check intervals based on confidence levels rather than fixed intervals.
Handle streaming and incomplete responses safely: When processing streaming AI output, use permissive parsing that can handle incomplete or improperly formatted content, prioritizing safe rendering over strict specification compliance.
Example Implementation:
// Good: Core library emits raw finish reason
if (finishReason && finishReason !== FinishReason.STOP) {
yield {
type: GeminiEventType.Finished,
value: finishReason // Raw enum value
};
}
// Good: UI layer handles user-facing messages
const finishReasonMessages: Record<string, string> = {
'MAX_TOKENS': '⚠️ Response truncated due to token limits.',
'SAFETY': '⚠️ Response stopped due to safety reasons.'
};
// Good: Schema with reasoning before conclusion
const schema = {
type: Type.OBJECT,
properties: {
reasoning: {
type: Type.STRING,
description: 'Your reasoning process'
},
confidence: {
type: Type.NUMBER,
description: 'Confidence level 0.0-1.0'
}
}
};
This approach ensures maintainable, robust AI integrations that can handle the unpredictable nature of model responses while providing clean separation of concerns.
Ensure CI/CD workflows maintain reliability by following these practices:
Use explicit script paths - Always use explicit paths when invoking scripts (e.g., ./build.ps1 for PowerShell or ./build.sh for bash) rather than relying on implicit path resolution. This ensures the runner can locate and execute scripts regardless of the current working directory.
name: Build packages (Windows) run: ./scripts/build-packages.ps1
name: Build packages (Unix) run: ./scripts/build-packages.sh ```
name: Set permissions run: chmod +x ./build.sh
name: Build run: ./build.sh ```
These practices will prevent common CI/CD failures and improve workflow reliability across different environments and contributor scenarios.
Tests should verify that different states, modes, or inputs produce meaningfully different behaviors, not just that code doesn’t crash. Focus on testing state transitions, edge cases, and behavioral changes rather than basic existence checks.
Use creative mocking strategies to make visual or complex behaviors testable. For UI components, mock styling functions to produce detectable output differences:
// Mock chalk.inverse to make highlighting testable
jest.mock('chalk', () => ({
inverse: (text) => `[${text}]`
}));
// Test that different states produce different outputs
expect(focusedOutput).toContain('t[e]st'); // highlighted
expect(unfocusedOutput).toContain('test'); // not highlighted
expect(focusedOutput).not.toEqual(unfocusedOutput); // crucial difference check
Test comprehensive edge cases and scenarios:
Verify actual behavioral changes rather than just testing that functions were called. For example, test that undo actually restores previous text content, not just that buffer.undo() was invoked.
Ensure each test runs in isolation by properly managing test state, mocks, and timers. Clean up all test artifacts in beforeEach/afterEach hooks rather than within individual tests to prevent state leakage and test interdependence.
Example:
describe('MyComponent', () => {
// ❌ Bad: Global mock without cleanup
const globalMock = vi.spyOn(global, 'setTimeout');
// ✅ Good: Proper setup and cleanup
let timeoutSpy: SpyInstance;
beforeEach(() => {
timeoutSpy = vi.spyOn(global, 'setTimeout');
});
afterEach(() => {
vi.restoreAllMocks();
vi.useRealTimers();
});
it('should handle timeouts', () => {
vi.useFakeTimers();
// Test implementation
});
});
Key practices:
Ensure tests verify real operations and integration scenarios rather than just basic concepts or type definitions. Many test suites contain placeholder tests that only check if functions exist or verify simple type structures, but fail to test the actual behavior and interactions that matter in production.
Tests should cover:
Example of inadequate testing:
it("should understand queue concepts", () => {
type QueueItem = { id: string; callback: string; payload: unknown; };
const testQueueItem: QueueItem = { id: "queue-123", callback: "processData", payload: { data: "test" } };
expect(testQueueItem.id).toBeDefined(); // Only tests type structure
});
Example of proper functional testing:
it("should process queue items and handle retries", async () => {
const agent = await getAgentByName(env.TEST_AGENT, "queue-test");
// Test actual queue operations
await agent.enqueue("processData", { data: "test" });
const result = await agent.processQueue();
expect(result.processed).toBe(1);
expect(result.failed).toBe(0);
});
it("should sync state between multiple clients", async () => {
const client1 = new AgentClient({ agent: "TestAgent", name: "client1" });
const client2 = new AgentClient({ agent: "TestAgent", name: "client2" });
const client2Updates = [];
client2.onStateUpdate = (state) => client2Updates.push(state);
client1.setState({ count: 5 });
// Verify real multi-client synchronization
expect(client2Updates).toContainEqual({ count: 5 });
});
This approach ensures tests provide meaningful coverage of how systems actually behave in production rather than just verifying that code compiles or basic structures exist.
Always wrap potentially unsafe operations (like JSON parsing, Buffer operations, or API calls) in try-catch blocks with appropriate error handling. Ensure error messages are user-friendly and actionable.
Example:
// Bad: Unsafe operation without error handling
const data = Buffer.from(input, "base64").toString("utf8");
const config = JSON.parse(toolCall.function.arguments);
// Good: Proper error handling with user-friendly messages
try {
const data = Buffer.from(input, "base64").toString("utf8");
return data;
} catch (error) {
throw new Error("Invalid data format provided. Please check your input.");
}
try {
const config = JSON.parse(toolCall.function.arguments);
return config;
} catch (error) {
throw new Error("Invalid configuration format. Please verify the syntax.");
}
Key points:
Always handle errors explicitly and preserve their context. Never silently catch and discard errors as this hides bugs and makes debugging difficult. When re-throwing errors, include the original error as the cause to maintain the stack trace. In UI components, convert errors to user-friendly messages while logging technical details at appropriate levels.
Example of proper error handling:
// ❌ Bad - Silently swallowing error
try {
await apiRequest();
} catch {
// Error silently ignored
}
// ❌ Bad - Losing error context
try {
await apiRequest();
} catch (error) {
throw new Error('API request failed');
}
// ✅ Good - Preserving context and handling appropriately
try {
await apiRequest();
} catch (error) {
// Log technical details
logger.error('API request failed', error);
// In UI: Show user-friendly message
toast.showError(
new Error('Unable to complete request', { cause: error }),
'Action failed'
);
// In services: Re-throw with context
throw new OperationalError(
'API request failed',
{ cause: error }
);
}
Maintain consistent parameter names and interface patterns across LLM implementations to improve maintainability and prevent integration issues. This includes:
Example:
// INCORRECT
if (!llm.bindTools) {
throw new LLMServiceError("LLM doesn't support binding tools");
}
const tokens = llmOutput?.tokenUsage?.completionTokens;
// CORRECT
if (typeof llm.withStructuredOutput !== 'function') {
throw new LLMServiceError("LLM doesn't support structured output");
}
const tokens = llmResult?.llmOutput?.tokenUsage?.completionTokens;
This standardization:
Documentation should explain rationale and be technically precise. Focus on:
Good example:
// editor.selectionHighlightBackground is used because it's always
// partially transparent, which prevents obscuring the selection
// when repurposed here
this.decorationType = vscode.window.createTextEditorDecorationType({
backgroundColor: new vscode.ThemeColor("editor.selectionHighlightBackground")
});
Bad example:
// Check if there is a trailing line
// This trims the selection if needed
Better example:
// If the user selected onto a trailing line but didn't actually include
// any characters in it, they don't want to include that line, so trim it off
For API documentation and examples, always verify that parameter names match the actual implementation and all required parameters are included with appropriate descriptions of their purpose.
Ensure your comparison algorithms handle edge cases properly and avoid common pitfalls:
// Problematic: Direct comparison may fail due to trailing whitespace
if (lineA === lineB) { /* ... */ }
// Better: Normalize before comparing when appropriate
if (lineA.trimEnd() === lineB.trimEnd()) { /* ... */ }
// Problematic: 'model' shadows the outer parameter
for (const model of specificModels) {
if (model.toLowerCase() === model) { // Always true!
return true;
}
}
// Better: Use distinct variable names
for (const specificModel of specificModels) {
if (model.toLowerCase() === specificModel.toLowerCase()) {
return true;
}
}
// Problematic: Breaking loop on first non-match may skip valid items
for (let i = chatHistory.length - 1; i >= 0; i--) {
if (item.message.role !== "assistant") {
break; // Stops looking at earlier messages
}
}
// Better: Continue searching when appropriate
for (let i = chatHistory.length - 1; i >= 0; i--) {
if (item.message.role !== "assistant") {
continue; // Skips this item but continues searching
}
// Process assistant messages
}
// Problematic: Strict equality might miss semantically equivalent items
if (i.id.providerTitle === item.id.providerTitle) {
// Only checks exact IDs, might miss different references to same resource
}
// Better: Consider what equality means in this context
if ((i.id.providerTitle === item.id.providerTitle) ||
(i.uri && item.uri && i.uri.value === item.uri.value)) {
// Checks both ID equality and URI reference equality
}
Prefer settings.json over environment variables and CLI flags for user configuration options. Environment variables should be reserved for system-level configuration or cases where the setting must be available before settings.json is loaded. CLI flags should be used for options that users frequently change between invocations.
Settings.json provides better user experience because:
Example of migrating an environment variable to settings:
// Before: checking environment variable directly
const maxDirs = parseInt(process.env.GEMINI_MEMORY_DISCOVERY_MAX_DIRS ?? '', 10) || 200;
// After: using settings.json
interface Settings {
memoryDiscoveryMaxDirs?: number;
}
// In code:
const maxDirs = settings.memoryDiscoveryMaxDirs ?? 200;
Reserve CLI flags for options that users need to change frequently (like --model for testing different models) and environment variables for system-level configuration that must be available during early initialization.
Always provide sensible default or fallback values for configuration properties to prevent undefined states that can block users or cause application errors. Configuration properties should never be left in an undefined state that prevents normal application functionality.
When defining configuration properties, especially those that come from external sources (servers, user settings, migrations), include appropriate fallback values using logical OR operators or default parameter values.
Example of proper fallback implementation:
// Good: Provides fallback to prevent undefined state
const selectedProvider =
(currentMode === "plan" ? apiConfiguration?.planModeApiProvider : apiConfiguration?.actModeApiProvider) || "cline"
// Good: Default parameter with fallback URL
const CreditLimitError: React.FC<CreditLimitErrorProps> = ({
buyCreditsUrl = "https://api.cline.bot/dashboard/account?tab=credits&redirect=true",
// other props...
}) => {
// Good: Explicit default value to prevent UI flashing
const defaultState = {
welcomeViewCompleted: false, // Default to show welcome unless overridden
// other defaults...
}
This practice is especially critical for:
The fallback values should represent the most sensible default behavior for new users or error recovery scenarios.
Configure timeout values based on empirical testing and user experience requirements rather than arbitrary durations. Analyze actual system behavior to determine appropriate timeout thresholds that balance responsiveness with reliability.
For user-facing operations, implement progressive feedback mechanisms - start with shorter timeouts for warnings while allowing longer timeouts for actual failures. For example, warn users after 7 seconds but don’t abandon the operation until 15 seconds.
For system operations, test with realistic scenarios to determine optimal values. Shell integration consistently emits initial chunks within milliseconds, so a 500ms timeout is sufficient for detecting unresponsive processes.
// Good: Evidence-based timeout with progressive feedback
let checkpointsWarningTimer: NodeJS.Timeout | null = null
checkpointsWarningTimer = setTimeout(async () => {
if (!checkpointsWarningShown) {
checkpointsWarningShown = true
this.taskState.checkpointTrackerErrorMessage =
"Checkpoints are taking longer than expected to initialize..."
await this.postStateToWebview()
}
}, 7_000) // Warn at 7s, but don't abandon until 15s
// Good: Tested timeout for system operations
const timeoutMs = 500 // Verified: shell integration emits chunks within milliseconds
firstChunkTimeout = setTimeout(() => {
// Handle timeout case
}, timeoutMs)
Always include timeout handling to prevent indefinite blocking and maintain application responsiveness, especially for network operations and external process interactions.
When handling potentially null or undefined values, implement explicit null checks and provide safe default values rather than allowing null values to propagate through the system. This prevents null reference errors and ensures predictable behavior.
Key practices:
Example from MultiselectInput validation:
@field_validator("value", mode="before")
@classmethod
def validate_value(cls, v: Any, _info):
# Handle None safely during construction
if v is None:
return []
if not isinstance(v, list):
msg = f"MultiselectInput value must be a list. Got: {type(v)}"
raise TypeError(msg)
# ... rest of validation
This pattern ensures that null values are caught early and converted to safe, usable defaults, preventing downstream null reference issues while maintaining clear error messages for invalid non-null values.
Security mechanisms should be tested for both success and failure scenarios to ensure they properly enforce boundaries. Don’t just test that security features work when enabled - also verify they correctly block unauthorized access when disabled or misconfigured.
For CORS implementations, test that cross-origin requests fail without proper headers:
it("should reject cross-origin requests without CORS headers", async () => {
const request = new Request("http://localhost/agents/TestAgent/test", {
method: "POST",
headers: {
Origin: "https://malicious-site.com"
}
});
const response = await routeAgentRequest(request, env, { cors: false });
expect(response.status).toBe(403); // or appropriate error status
expect(response.headers.get("Access-Control-Allow-Origin")).toBeNull();
});
For authentication flows, create comprehensive test suites that cover edge cases, error conditions, and security boundaries rather than just happy path scenarios. Complex security mechanisms like OAuth require dedicated test coverage to ensure all attack vectors are properly defended against.
Environment variables in CI/CD workflows should be organized consistently using structured env sections rather than inline declarations, and should account for platform-specific requirements. This improves maintainability, readability, and prevents environment-related failures across different operating systems.
Use the env field at the step or job level instead of inline variable assignments:
# Preferred approach
- name: Package and Publish Extension
env:
VSCE_PAT: ${{ secrets.VSCE_PAT }}
OVSX_PAT: ${{ secrets.OVSX_PAT }}
CLINE_ENVIRONMENT: production
run: vsce package --out "cline-${{ steps.get_version.outputs.version }}.vsix"
# Instead of inline
run: CURRENT_ENVIRONMENT=production vsce package --out "file.vsix"
For cross-platform compatibility, explicitly set platform-specific environment variables when needed:
run: |
# Default the encoding to UTF-8 - It's not the default on Windows
PYTHONUTF8=1 PYTHONPATH=.github/scripts python -m coverage_check
This approach centralizes environment configuration, makes dependencies explicit, and prevents platform-specific failures in automated workflows.
Design your API interfaces to be provider-agnostic rather than tightly coupled to specific service providers. This improves flexibility, maintainability, and makes future provider changes less disruptive.
Key practices:
Example - Instead of:
const OPENAI_STREAM_IDLE_TIMEOUT_MS: u64 = 300_000;
const OPENAI_STREAM_MAX_RETRIES: u64 = 10;
// Direct provider-specific implementation
async fn generate_summary(transcript: &[TranscriptEntry], model: &str) -> Result<String> {
// Provider-specific implementation
let api_key = get_openai_api_key()?;
let url = "https://api.openai.com/v1/chat/completions";
// Rest of implementation...
}
Prefer:
const DEFAULT_STREAM_IDLE_TIMEOUT_MS: u64 = 300_000;
const DEFAULT_STREAM_MAX_RETRIES: u64 = 10;
// Provider-agnostic implementation using configuration
async fn generate_summary(
transcript: &[TranscriptEntry],
model: &str,
config: &Config,
) -> Result<String> {
// Use configuration for provider details
let api_key = config.get_api_key()?;
let base = config.model_provider.base_url.trim_end_matches('/');
let url = format!("{}/chat/completions", base);
// Rest of implementation...
}
This approach makes your codebase more resilient to changes in provider APIs and allows for easier testing and switching between different service providers.
Always use proper XML entity escaping instead of CDATA blocks when embedding XML-like content within XML documents. CDATA sections can be vulnerable to XML injection attacks if the content isn’t properly validated or controlled.
For example, instead of:
<tool_use><![CDATA[
<update_todo_list>
<todos>
[ ] First item
[ ] Second item
</todos>
</update_todo_list>
]]></tool_use>
Use properly escaped XML entities:
<tool_use>
<update_todo_list>
<todos>
[ ] First item
[ ] Second item
</todos>
</update_todo_list>
</tool_use>
This practice prevents XML injection vulnerabilities that could allow attackers to manipulate XML processing, potentially leading to data exposure, unauthorized access, or other security breaches in systems that parse and process your XML documents.
Always use the project’s structured logger instead of direct console methods (console.log, console.error, etc.). This ensures consistent log formatting, proper level-based filtering, and integration with monitoring systems.
Problems with direct console logging:
Good logging practice:
// AVOID: Direct console logging
console.log('Database pool created'); // Hard to filter out in production
console.error('Error handling streaming chunk:', error); // Bypasses error tracking
// BETTER: Use the structured logger with appropriate levels
this.logger.debug('Database pool created'); // Can be silenced in production
this.logger.info(`Generated workflow for prompt: ${flags.prompt}`); // Informational messages
this.logger.warn('The output file already exists. It will be overwritten.'); // Warnings
this.logger.error(`Error processing prompt "${flags.prompt}": ${errorMessage}`); // Actual errors
For debug-only logging, conditionally log based on environment or debug flags rather than leaving console statements that will always execute:
// BETTER: Conditional debug logging
if (isDebugMode) {
this.logger.debug(`Connection parameters for ${nodeType}:`, warnings);
}
Ensure log levels match the message severity - use error only for actual failures, and info/debug for status messages to prevent false alarms in monitoring systems.
Break down complex or deeply nested code into smaller, well-named helper functions to improve readability and maintainability. Extract code into helpers when:
Example of improving complex nested code:
Before:
function processNextEditData(filePath, beforeContent, afterContent, cursorPosBeforeEdit, ...) {
// Get the current context data
const currentData = (global._editAggregator as any).latestContextData || {
configHandler: data.configHandler,
getDefsFromLspFunction: data.getDefsFromLspFunction,
recentlyEditedRanges: [],
recentlyVisitedRanges: [],
};
void processNextEditData(
beforeAfterdiff.filePath,
beforeAfterdiff.beforeContent,
beforeAfterdiff.afterContent,
cursorPosBeforeEdit,
cursorPosAfterPrevEdit,
this.ide,
currentData.configHandler,
currentData.getDefsFromLspFunction,
currentData.recentlyEditedRanges,
currentData.recentlyVisitedRanges,
currentData.workspaceDir,
);
}
After:
interface ProcessNextEditDataParams {
filePath: string;
beforeContent: string;
afterContent: string;
cursorPosBeforeEdit: Position;
cursorPosAfterPrevEdit: Position;
ide: IDE;
configHandler: ConfigHandler;
getDefsFromLspFunction: GetLspDefinitionsFunction;
recentlyEditedRanges: RecentlyEditedRange[];
recentlyVisitedRanges: AutocompleteCodeSnippet[];
workspaceDir: string;
}
function getCurrentContextData(): ContextData {
return (global._editAggregator as any).latestContextData || {
configHandler: data.configHandler,
getDefsFromLspFunction: data.getDefsFromLspFunction,
recentlyEditedRanges: [],
recentlyVisitedRanges: [],
};
}
function processNextEditData(params: ProcessNextEditDataParams) {
const currentData = getCurrentContextData();
// Process using structured parameters...
}
---
## Sanitize all dynamic content
<!-- source: n8n-io/n8n | topic: Security | language: Other | updated: 2025-07-17 -->
Always sanitize dynamic content before rendering to prevent XSS and injection attacks. This includes HTML content, CSS styles, and executable scripts. Use appropriate sanitization methods based on content type:
1. For HTML content:
```javascript
// Bad
return props.content.html;
// Good
return DOMPurify.sanitize(props.content.html, {
ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'span', 'div'],
ALLOWED_ATTR: ['class']
});
{{{message}}}
{{message}}
3. For CSS:
- Use strict whitelisting of allowed properties
- Validate against injection patterns
- Consider using CSS-in-JS solutions with built-in sanitization
4. For scripts:
- Avoid dynamic script execution (new Function(), eval())
- Use strict CSP headers
- Implement proper sandboxing for user-provided code
Never trust user input or third-party content. Always validate and sanitize before rendering.
---
## centralize configuration management
<!-- source: cline/cline | topic: Configurations | language: TypeScript | updated: 2025-07-17 -->
Consolidate related configuration settings into dedicated config objects or files rather than scattering hardcoded values throughout the codebase. Separate different types of configuration (API endpoints, timeouts, credentials) into distinct config sections to improve maintainability and avoid coupling.
Use environment variables for sensitive data like API keys and DSNs instead of hardcoding them. Organize configuration with clear separation of concerns - for example, having separate `mcpBaseUrl` and `apiBaseUrl` rather than reusing the same URL for different purposes.
Create centralized configuration objects for related constants:
```typescript
// Instead of scattered constants
const DEBUG_PORT = 9222
const TIMEOUT_MS = 4000
const DEFAULT_RETRIES = 3
// Use centralized config
const browserConfig = {
debugPort: 9222,
timeoutMs: 4000,
defaultRetries: 3
}
// Separate API configurations
const apiConfig = {
baseUrl: process.env.API_BASE_URL || "https://api.example.com",
mcpBaseUrl: process.env.MCP_BASE_URL || "https://mcp.example.com"
}
Move shared configuration to dedicated config files in shared folders, and provide sensible defaults for all configuration values to ensure robust fallback behavior.
Choose variable, function, and type names that clearly communicate their purpose and meaning without requiring additional context or comments. Names should be self-documenting and unambiguous to future developers.
Replace generic or unclear identifiers with descriptive alternatives:
enableExpandedMcpPanelState over ambiguous string states like "collapsed" | "expanded"const CONTEXT_EXPANSION_LINES = 3 instead of hardcoded 3"claude_message.json" - use descriptive constants or derive from existing naming conventionsFor complex types, ensure the type structure is self-explanatory:
// Instead of unclear typing
private contextHistoryUpdates: Map<number, [number, Map<number, ContextUpdate[]>]>
// Use descriptive types
private contextHistoryUpdates: Map<number, [EditType, Map<number, ContextUpdate[]>]>
When names become long for clarity, prioritize understanding over brevity. A longer, clear name is preferable to a short, ambiguous one that requires documentation to understand.
Documentation should focus exclusively on current, active functionality rather than including historical context, deprecated features, or legacy modes. Remove sections that explain how things “used to work” or provide extensive support for outdated approaches that have minimal user adoption.
Avoid making unverified claims about external implementations or including speculative information. If historical context is truly necessary, move it to pull request comments or separate historical documentation rather than cluttering user-facing docs.
For example, instead of:
> **Note:** The Memory Import Processor has evolved to support both modern compatibility with CLAUDE.md and the original GEMINI.md modular import philosophy. This dual-mode approach reflects feedback from the community...
## Import Modes: CLAUDE.md Compatibility vs. Original GEMINI.md
| Feature | CLAUDE.md Compatibility Mode (Current Default) | Original GEMINI.md Mode (Legacy) |
Write:
# Memory Import Processor
The Memory Import Processor allows you to modularize your files by importing content from other markdown files using the `@file.md` syntax.
Similarly, replace generic template text with actual current information, and remove unnecessary elements like table of contents for short documents. Keep documentation concise and focused on what users need to know to use the current version effectively.
Replace direct console.log, console.warn, and console.error calls with a centralized logging abstraction. This ensures logs are consistently formatted, properly categorized by severity, and can be filtered or disabled in production environments.
Benefits:
Implementation:
logger.debug() - For development-only informationlogger.info() - For normal operational messageslogger.warn() - For concerning but non-critical issueslogger.error() - For failures that require attentionExample:
Instead of:
console.log("[CodeIndexManager] Attempting to recover from error state before starting indexing.")
console.log("APi Protocol:", apiProtocol)
console.error(`Error parsing Ollama models response: ${JSON.stringify(parsedResponse.error, null, 2)}`)
Use a logger:
logger.info("[CodeIndexManager] Attempting to recover from error state before starting indexing.")
logger.debug("API Protocol:", apiProtocol)
logger.error("Error parsing Ollama models response:", { error: parsedResponse.error })
Use names that clearly convey purpose and maintain consistency across related components. Avoid generic identifiers (like dir) in favor of descriptive ones (like codex_home), and ensure placeholder names in string templates are self-explanatory (prefer SUMMARY_TEXT over {}). For related functions or elements, establish consistent naming patterns with meaningful symmetry, particularly for operations that are conceptually opposite.
When naming variables, functions, or constants:
openai_request_max_retries when it applies to all providers)fully_qualified_tool_name(), its counterpart should be parse_fully_qualified_tool_name())Example:
// Poor naming
const TEMPLATE: &str = "Summary: {}";
fn get_name(s: &str, t: &str) -> String { /* ... */ }
fn extract(name: &str) -> (&str, &str) { /* ... */ }
// Better naming
const SUMMARY_TEMPLATE: &str = "Summary: {SUMMARY_TEXT}";
fn fully_qualified_tool_name(server: &str, tool: &str) -> String { /* ... */ }
fn parse_fully_qualified_tool_name(name: &str) -> (&str, &str) { /* ... */ }
Avoid duplicate proxy configuration across your application by establishing a single point of proxy setup and leveraging built-in proxy support where available. Multiple proxy configurations can lead to conflicts, inconsistent behavior, and maintenance overhead.
Key principles:
Example from the discussions:
// ❌ Avoid: Multiple proxy configurations
export class MCPOAuthProvider {
private static readonly REDIRECT_PORT = 7777; // Hardcoded port causes conflicts
}
// In another file
const client = new OAuth2Client({
transporter: new Gaxios({ proxy: proxyUrl }) // Duplicate proxy setup
});
// ❌ Avoid: Redundant proxy setup
if (config.getProxy()) {
// setGlobalDispatcher already called in core/client.ts
}
// ✅ Better: Centralized approach
// In core/client.ts - set once globally
setGlobalDispatcher(proxyAgent);
// OAuth2Client automatically reads from environment
const client = new OAuth2Client({
// No manual transporter needed - uses env proxy settings
});
// Use dynamic port allocation
const server = http.createServer();
server.listen(0); // Let Node.js choose available port
This approach ensures consistent proxy behavior across all network requests while avoiding configuration conflicts and reducing maintenance burden.
Configuration files defining operations that generate data outputs must always include a <save_to> element specifying the output location. Follow established patterns for similar operations, typically using predictable paths like .roo/temp/pr-[PR_NUMBER]/[operation]-output.{json|diff}. This ensures operation outputs are consistently stored and easily locatable by other processes.
Example:
<operation name="fetch_comments">
<description>Get all comments on the PR</description>
<command>gh pr view [PR_NUMBER] --repo [owner]/[repo] --json comments --jq '.comments'</command>
<output_format>JSON array of comments</output_format>
<save_to>.roo/temp/pr-[PR_NUMBER]/pr-comments.json</save_to>
</operation>
When working with graph structures, collections, or relationship mappings, ensure each element is processed exactly once to maintain algorithmic integrity. Implement proper tracking mechanisms to prevent duplicate counting or processing of elements, especially in scenarios involving:
For example, instead of unconditionally adding items to collections:
// Problematic: Elements may be added multiple times
this.runOrder.push(runKey);
// Better: Check before adding to prevent duplicates
if (!this.runOrder.includes(runKey)) this.runOrder.push(runKey);
When counting connections in graphs, track which connections have been counted:
// Problematic: May count self-loops twice
function countNodeConnections(nodeId, connections) {
let count = 0;
// Count outgoing connections
if (connections[nodeId]) {
// Count outgoing logic...
count += outgoingCount;
}
// Count incoming connections (may include duplicates with self-loops)
for (const [sourceNodeId, nodeConnections] of Object.entries(connections)) {
// Count incoming logic that doesn't account for sourceNodeId === nodeId
count += incomingCount;
}
return count;
}
// Better: Use a Set to track unique connections
function countNodeConnections(nodeId, connections) {
const countedConnections = new Set();
let count = 0;
// Add logic to track unique connection IDs to prevent double-counting
// Only increment count for connections not already in the Set
return count;
}
This approach prevents algorithmic errors that affect calculations, state management, and the correctness of graph operations.
Never hardcode environment-specific values or feature states directly in your code. Instead, use environment variables, configuration files, or feature flag systems to manage these values dynamically.
For environment URLs:
// BAD
window.location.replace('https://stage.ciaraai.com/workflows');
// GOOD
window.location.replace(process.env.VUE_APP_PLATFORM_URL + '/workflows');
For feature flags and UI components:
// BAD
<N8nBadge class="ml-4xs">{{ i18n.baseText('generic.upgrade') }}</N8nBadge>
// GOOD
<N8nBadge v-if="!settingsStore.isEnterpriseFeatureEnabled[EnterpriseEditionFeature.EnforceMFA]" class="ml-4xs">
{{ i18n.baseText('generic.upgrade') }}
</N8nBadge>
Hardcoded configurations are difficult to maintain, lead to environment-specific bugs, and can result in misleading UI elements for users. Always retrieve configuration values from the appropriate source at runtime to ensure your application behaves correctly across all environments and user scenarios.
When implementing watchers in Vue applications, ensure they are configured appropriately for the data structures they observe. Two common pitfalls to avoid:
deep: true for complex data structures: When watching arrays or objects that might be modified in-place (push, pop, property updates), enable deep watching to detect these changes:watch(
() => props.messages,
async (messages) => {
// Handler logic
},
{ immediate: true, deep: true } // Enable deep watching for arrays/objects
)
Without deep watching, the watcher will only trigger when the reference changes, not when items are added or properties modified.
// Less optimal - watches entire object reference
watch(
() => selected,
// Handler logic
)
// More optimal - watches just the ID property
watch(
() => selected?.id,
// Handler logic
)
This prevents unnecessary watcher triggers when unrelated properties change and makes your reactivity system more predictable and efficient.
Never hardcode sensitive information such as passwords, API keys, or authentication tokens in source code, configuration files, or container definitions. These can be exposed through version control systems, shared repositories, or compromised container images.
Instead:
Example - Instead of:
FROM n8nio/n8n
ENV N8N_BASIC_AUTH_ACTIVE=true
ENV N8N_BASIC_AUTH_USER=Tre
ENV N8N_BASIC_AUTH_PASSWORD=Npt9854$
Better approach:
FROM n8nio/n8n
ENV N8N_BASIC_AUTH_ACTIVE=true
# Credentials will be provided at runtime
# docker run -e N8N_BASIC_AUTH_USER=username -e N8N_BASIC_AUTH_PASSWORD=password n8n-image
For build-time configuration, use ARG instead of ENV for sensitive values that shouldn’t persist in the image.
Always validate and sanitize user inputs, especially when constructing commands or file paths. Use established security libraries instead of implementing custom parsing logic, and implement proper validation that prevents attacks while avoiding false positives.
Key practices:
Example of secure command parsing:
// Instead of unsafe split
const parts = command.split(/\s+/); // Unsafe - doesn't handle quotes
// Use secure parsing
const parts = splitCommandSafely(command);
if (!parts) {
return 'Command parsing failed: unmatched quotes';
}
// Validate path traversal
const rootDir = path.resolve(this.config.getTargetDir());
const resolvedDir = path.resolve(rootDir, params.directory);
if (!resolvedDir.startsWith(rootDir + path.sep) && resolvedDir !== rootDir) {
return 'Directory traversal is not allowed. Path must be within the project root.';
}
This approach prevents injection attacks, handles edge cases properly, and maintains functionality while ensuring security.
Maintain consistent data formats, parameter units, and interface patterns across API implementations. This includes:
Example of problematic inconsistencies:
// Inconsistent MIME type mapping
const mimeTypes: Record<string, string> = {
".png": "image/png",
".jpg": "image/jpeg",
// Missing MIME type for supported format
// .avif is in SUPPORTED_IMAGE_FORMATS but not mapped here
}
// Inconsistent parameter unit description
openAiApiTimeout: z.number().optional().describe("Timeout in milliseconds"),
// But actually handled as minutes in implementation:
const timeoutMs = (options.timeout ?? 10) * 60 * 1000
// Inconsistent message format handling
// Don't convert structured data to plain text when the API supports JSON
const args = [
"-p",
JSON.stringify(messages), // Correct: Preserve message structure
"--system-prompt",
systemPrompt
]
To maintain consistency:
Implement explicit resource limits and monitoring to prevent performance degradation and memory issues. This includes:
Example implementation:
class ResourceAwareProcessor {
private static readonly MAX_BUFFER_SIZE = 1024 * 1024; // 1MB
private static readonly MAX_CACHE_ENTRIES = 1000;
private buffer: Buffer | null = null;
async processData(data: string): Promise<void> {
// Early size check
if (Buffer.byteLength(data) > this.MAX_BUFFER_SIZE) {
throw new Error(`Data exceeds maximum size of ${this.MAX_BUFFER_SIZE} bytes`);
}
// Reuse buffer if possible
if (!this.buffer) {
this.buffer = Buffer.alloc(this.MAX_BUFFER_SIZE);
}
// Process with size awareness
try {
// ... processing logic
} catch (error) {
console.warn(`Processing warning: ${error.message}`);
}
}
clearBuffer(): void {
this.buffer = null;
}
}
This approach:
Always validate data existence and type before accessing properties or methods to prevent runtime errors from null/undefined values. This includes:
Example of unsafe code:
function toolCallStateToSystemToolCall(state: ToolCallState): string {
return state.toolCall.function.name; // Unsafe - multiple potential null points
}
Safe version:
function toolCallStateToSystemToolCall(state: ToolCallState): string {
if (!state?.toolCall?.function) {
throw new Error("Invalid tool call state");
}
return state.toolCall.function.name ?? "unknown";
}
Key practices:
This prevents the most common causes of runtime errors and improves code reliability.
Avoid circular dependencies in asynchronous code paths that can lead to deadlocks or indefinite blocking. When using async/await, ensure that promise chains have clear resolution paths and aren’t dependent on their own completion. Be particularly careful with initialization patterns and refresh mechanisms.
Example of problematic code:
// PROBLEMATIC: Creates a deadlock
public async getSessions(): Promise<AuthSession[]> {
await this.initialRefreshAttempt; // Waits for refresh to complete
// ...
}
private async refreshSessions(): Promise<void> {
const sessions = await this.getSessions(); // Calls getSessions which waits for refreshSessions
// ...
}
constructor() {
this.initialRefreshAttempt = this.refreshSessions();
}
Example of fixed code:
// FIXED: Avoids deadlock by breaking circular dependency
public async getSessions(): Promise<AuthSession[]> {
// Don't await initialRefreshAttempt here
// ...
}
private async refreshSessions(): Promise<void> {
const sessions = await this.getSessions();
// ...
}
constructor() {
this.initialRefreshAttempt = this.refreshSessions();
}
Additionally:
Configuration examples should be complete, accurate, and ready to use without modification. This applies to both code snippets and configuration file examples.
For code examples that use configuration:
import os when using os.environ)For configuration file examples:
Example of good practice:
# Complete example with imports
import os
# Configure Bearer authorization
configuration = openapi_client.Configuration(
access_token = os.environ["BEARER_TOKEN"]
)
Example of good configuration documentation:
{
"name": "commit",
"description": "Generate a commit message for staged changes",
"params": { "includeUnstaged": true }
}
With explanation: “If includeUnstaged is set to true, then unstaged changes are also included in the prompt, otherwise only staged changes are included.”
Follow consistent naming conventions for all identifiers to improve code quality, accessibility, and test reliability. Ensure correct spelling and adhere to established project patterns.
Key practices:
// ❌ Incorrect
<label for="avalableInMCP">
data-test-id="workflow-settings-vailable-in-mcp"
// ✅ Correct
<label for="availableInMCP">
data-test-id="workflow-settings-available-in-mcp"
thumbsUp) or kebab-case (thumbs-up) and use consistentlyThis approach helps prevent broken references between HTML elements, ensures tests target the correct elements, and makes code more maintainable by following predictable patterns.
Cache computation results in React components to prevent unnecessary recalculations during re-renders, which can significantly impact application performance. Apply these optimization techniques in three key areas:
// Optimized approach import { createSelector } from ‘reselect’; const memoizedSelector = createSelector( [selectCurrentToolCall], (toolCall) => toolCall ); const currentToolCall = useAppSelector(memoizedSelector);
2. **Expensive calculations**: Move computations with O(n) or higher complexity outside render loops and cache them:
```tsx
// Suboptimal approach - O(n²) complexity
{history.map(item => {
const latestSummaryIndex = findLatestSummaryIndex(history);
// rest of render logic
})}
// Optimized approach - O(n) complexity
const latestSummaryIndex = useMemo(() =>
findLatestSummaryIndex(history),
[history]
);
{history.map(item => {
// use latestSummaryIndex
// rest of render logic
})}
<div style={{ fontSize: getFontSize() }}>
// Optimized approach const fontSize = useFontSize(); <div style={{ fontSize }}>
When implementing these optimizations, focus on functions that perform expensive calculations or create new object references, especially those called frequently during renders or within loops.
---
## Tests must assert
<!-- source: continuedev/continue | topic: Testing | language: Python | updated: 2025-07-16 -->
Test methods should contain active, uncommented code that includes at least one assertion to verify expected behavior. Commented-out test code provides zero value and creates a false sense of security by appearing to test functionality while actually testing nothing.
Instead of:
```python
def testGetResponse(self):
# inst = self.make_instance(include_optional=False)
# self.assertEqual(inst.message, "Expected message")
Write:
def testGetResponse(self):
inst = self.make_instance(include_optional=False)
self.assertIsNotNone(inst)
self.assertEqual(inst.message, "Expected message")
Every test method should verify specific functionality by executing the code under test and validating results through appropriate assertions. Tests without assertions or with only commented code will always pass regardless of code correctness, defeating the purpose of having tests.
Always centralize configuration constants in a shared location and import them rather than duplicating values across the codebase. This prevents drift between frontend and backend configurations, reduces errors from manual updates, and makes configuration changes easier to manage.
For example, instead of:
// In UI component
<input
type="range"
min="0"
max="1"
step="0.05"
value={codebaseIndexConfig.codebaseIndexSearchMinScore || 0.4}
/>
// In another file
const defaultMinScore = 0.4;
Do this:
// In shared constants file
export const SEARCH_MIN_SCORE = 0.4;
// In UI component
import { SEARCH_MIN_SCORE } from "@/constants/config";
<input
type="range"
min="0"
max="1"
step="0.05"
value={codebaseIndexConfig.codebaseIndexSearchMinScore || SEARCH_MIN_SCORE}
/>
This approach also applies to default values derived from dynamic sources, where you should establish a clear fallback chain:
const displayValue = value ?? modelInfo?.maxTokens ?? DEFAULT_MAX_TOKENS
When centralizing configuration constants:
Environment and configuration values should be explicit, visible, and environment-aware. Avoid hardcoded production values, hidden configuration properties, and complex environment variable logic. Instead:
// Good export const skipAuth = process.env.SKIP_AUTH === ‘true’ || false;
2. Make configuration properties visible and customizable:
```typescript
// Bad
class Config {
@Env('DB_NAME')
database: string = 'production_db'; // Hardcoded production value
}
// Good
class Config {
@Env('DB_NAME')
database: string = 'local_db'; // Development-friendly default
@Env('API_URL')
apiUrl: string = 'http://localhost:3000'; // Visible and configurable
}
// Good const DIST_DIR = process.env.DIST_DIR || join(__dirname, ‘dist’);
This approach improves maintainability, prevents production issues, and makes configuration more transparent for developers and operators.
---
## Pin actions securely
<!-- source: n8n-io/n8n | topic: CI/CD | language: Yaml | updated: 2025-07-15 -->
Always pin GitHub Actions to specific commit hashes rather than version tags to prevent supply chain attacks and ensure build reproducibility. This practice ensures that your workflow remains stable and secure even if the action's version tag is compromised or modified.
For example, use:
```yaml
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
Additionally:
- name: Setup Environment and Build Project
uses: ./.github/actions/setup-and-build
with:
node-version: 20.x
enable-caching: true
Always validate AI model capabilities and configurations before attempting to use them. This includes checking:
Example:
// Before using model features, validate capabilities
const provider = await client.providerRef.deref();
const modelCapabilities = {
supportsImages: provider?.apiHandler?.getModel()?.info?.supportsImages ?? false,
supportedDimensions: [768, 1536, 3072],
isModelAvailable: Boolean(routerModels[provider]?.[modelId])
};
// Use capabilities to make decisions
const imagesToInclude = modelCapabilities.supportsImages ? allImages : [];
if (!modelCapabilities.isModelAvailable) {
throw new Error(`Model ${modelId} is not available`);
}
This prevents runtime errors, improves reliability, and ensures optimal resource usage. It’s particularly important in AI applications where different models may have varying capabilities and requirements.
Avoid making multiple database queries when a single query can retrieve the required data. Each database roundtrip adds latency and increases system load. Before making a database call, check if the data is already available or if multiple queries can be combined into one.
Common patterns to avoid:
Example of inefficient pattern:
// Inefficient: Two separate queries for the same job
const job = await supabaseGetJobByIdOnlyData(req.params.jobId);
if (!job || job.team_id !== req.auth.team_id) {
return res.status(403).json({ success: false, error: "Access denied" });
}
const jobData = await supabaseGetJobsById([req.params.jobId]);
Better approach:
// Efficient: Single query with proper error handling
const jobData = await supabaseGetJobsById([req.params.jobId]);
if (!jobData || jobData.length === 0 || jobData[0].team_id !== req.auth.team_id) {
return res.status(403).json({ success: false, error: "Access denied or not found" });
}
When pagination is necessary due to database limits, ensure it’s truly required and document the reasoning clearly.
Never allow unrestricted public access (0.0.0.0/0) to database instances. Restrict database network access to only specific trusted IP ranges or VPC networks that require it, following the principle of least privilege. This prevents potential unauthorized access and data breaches.
Example of problematic configuration:
postgres_authorized_networks = [
{
name = "all"
value = "0.0.0.0/0"
}
]
Example of improved configuration:
postgres_authorized_networks = [
{
name = "internal-network"
value = "10.0.0.0/8"
},
{
name = "office-network"
value = "203.0.113.0/24"
}
]
Structure documentation to prevent information overload and improve readability by using appropriate organizational elements and callouts judiciously.
Key principles:
Break up complex information: When a single section contains multiple concepts or choices, use tabs, collapsible details, or separate sections to organize the content logically.
Use callouts appropriately: Reserve “important” admonitions for truly critical information. Use “tip” for helpful but non-essential information, and regular text for general explanations.
Avoid empty headings: Don’t have empty space between headings. Each heading should immediately be followed by content or subheadings.
Group related content: When documenting multiple related items (like components from the same provider), group them together under a common section.
Minimize visual clutter: Wrap lengthy code outputs or JSON responses in collapsible <details> sections when only specific parts are relevant to the reader.
Example of good organization:
## Configure MCP servers
### Install the server locally
1. Install the weather server:
```bash
uv pip install mcp_weather_server
:::tip Environment variables
Langflow passes environment variables from the .env file to MCP, but not global variables declared in the UI.
:::
This approach separates installation from configuration, uses tabs for different options, and reserves the tip callout for helpful supplementary information rather than critical instructions.
---
## AI response variability
<!-- source: langflow-ai/langflow | topic: AI | language: Markdown | updated: 2025-07-14 -->
When documenting AI model interactions, account for the non-deterministic nature of AI responses and avoid assumptions about specific outputs. AI models can produce different responses to identical inputs, and model behavior changes over time through updates and improvements.
Write documentation that remains accurate regardless of response variations:
```markdown
# Instead of assuming specific responses:
The LLM response is vague, though the Agent does know the current date.
# Use generic descriptions that account for variability:
This query demonstrates how an LLM, by itself, might not have access to
information or functions designed to address specialized queries. In this
example, the default OpenAI model provides a vague response, although the
agent does know the current date by using its internal `get_current_date` function.
Avoid describing models with performance or cost specifics that may become outdated. Instead of “this model is a good balance of performance and cost,” use “this model is a balanced model” or reference the provider’s current recommendations.
Include disclaimers when showing example AI responses: “The following is an example of a response returned from this tutorial’s flow. Due to the nature of LLMs and variations in your inputs, your response might be different.”
This approach ensures documentation remains useful as AI models evolve and helps users understand the inherent variability in AI systems.
Reduce unnecessary overhead in performance-related code by creating reusable patterns and avoiding verbose implementations. This applies to both production performance monitoring and development workflows like testing.
For performance measurement, avoid repetitive timing logic by creating wrapper functions that encapsulate the boilerplate:
// Instead of repeated start/end timing:
const authStart = performance.now();
await config.refreshAuth(settings.merged.selectedAuthType);
const authEnd = performance.now();
const authDuration = authEnd - authStart;
// Use a reusable wrapper:
trackStartupPerformance(async () => {
await config.refreshAuth(settings.merged.selectedAuthType);
}, 'authentication');
In tests, minimize execution time by avoiding unnecessary delays. Use minimal wait times when async operations require synchronization:
// Avoid: await wait(100); // Slows down test suite
// Prefer: await wait(1); // Minimal delay when needed
This approach reduces both runtime overhead in production code and development-time overhead in test execution, improving overall system efficiency and developer productivity.
Instead of making multiple small assertions that check individual fields or conditions, write single comprehensive assertions that verify the complete expected state. This approach makes tests more maintainable, provides better documentation of expected behavior, and makes test failures more informative.
Example - Instead of:
assert_eq!(tools[0]["type"], "function");
assert_eq!(tools[0]["name"], "shell");
assert!(tools.iter().any(|t| t.get("name") == Some(&name.clone().into())));
Prefer:
assert_eq!(tools, vec![
json!({
"type": "function",
"name": "shell"
}),
json!({
"type": "function",
"name": name
})
]);
This practice:
When dealing with complex objects that don’t implement PartialEq, consider implementing it to enable comprehensive assertions rather than checking fields individually.
Ensure that configuration files and settings are consistent with their intended functionality and maintain portability across different environments.
Key aspects to verify:
Example of improving path configuration:
// Problematic - hardcoded absolute path
const templatePath = 'C:\\Users\\orphe\\Downloads\\playwright-mcp.yaml';
// Better - relative path using Node.js path module
const templatePath = path.join(__dirname, 'playwright-mcp.yaml');
Example of aligning permissions with functionality:
# Problematic - empty groups but roleDefinition mentions using tools
roleDefinition: |-
You can use the `new_task` tool...
groups: []
# Better - groups include all necessary permissions
roleDefinition: |-
You can use the `new_task` tool...
groups:
- read
- edit
- command
- new_task
Names should accurately reflect their purpose and be used consistently throughout the codebase. This applies to props, function names, variables, and UI labels.
// Inconsistent - avoid this:
<EditFile changes={args.diff ?? ""} />
<EditFile changes={args.changes ?? ""} />
// Consistent - do this:
<EditFile changes={args.changes ?? ""} />
<EditFile changes={args.changes ?? ""} />
// Misleading - avoid this:
<span onClick={() => void dispatch(cancelStream())}>Pause</span>
// Clear and accurate - do this:
<span onClick={() => void dispatch(cancelStream())}>Cancel</span>
// Unclear semantics - avoid this:
<Switch onWarningText="This is a warning" />
// Clear semantics - do this:
<Switch warningText="This is a warning" />
Following these guidelines helps prevent bugs, improves code readability, and makes the codebase more maintainable.
Ensure UI elements’ visual state (e.g., disabled, active) always matches their actual behavior. When an element appears disabled, completely prevent the associated actions by:
This prevents users from encountering unexpected errors or broken states.
Example fix:
// Before: UI looks disabled but handler still works
<div
className={`${disabled ? "cursor-not-allowed" : "cursor-pointer"}`}
onClick={(e) => {
dispatch(toggleToolSetting(props.tool.function.name));
e.stopPropagation();
}}
>
// After: Handler respects disabled state
<div
className={`${disabled ? "cursor-not-allowed" : "cursor-pointer"}`}
onClick={(e) => {
if (!disabled) {
dispatch(toggleToolSetting(props.tool.function.name));
e.stopPropagation();
}
}}
>
Similarly, when providing keyboard shortcuts or handlers (like Escape to close dialogs), ensure the handlers are accessible in all relevant contexts to prevent broken interaction patterns.
Identify and eliminate redundant computations, network requests, and re-renders in React components to improve performance. Common patterns include memoizing functions that recreate on every render, debouncing user input to reduce API calls, and conditionally triggering side effects only when necessary.
Use useCallback for functions passed as props or used in dependency arrays:
const renderSegment = useCallback((segment: DisplaySegment): JSX.Element => {
// render logic
}, [dependencies])
Implement debouncing for user input to prevent excessive state updates:
const [localValue, setLocalValue] = useDebouncedInput(initialValue, onChange)
Separate side effects to trigger only when specific conditions change:
// Instead of combining multiple concerns in one useEffect
useEffect(() => {
if (isVisible) {
vscode.postMessage({ type: "fetchLatestMcpServersFromHub" })
}
}, [isVisible]) // Only fetch when visibility changes, not on dimension changes
Before implementing expensive operations, ask: “Is this computation/request/re-render actually necessary?” and “Can I reduce the frequency or scope of this operation?”
Always sanitize user-generated or externally sourced content before rendering it to prevent Cross-Site Scripting (XSS) vulnerabilities. Never use dangerouslySetInnerHTML with unsanitized content.
When handling user input or external data:
Bad practice:
// Dangerous - susceptible to XSS attacks
const renderTableCell = (content: string) => {
return <div dangerouslySetInnerHTML={{ __html: content }} />;
};
Good practice:
import DOMPurify from 'dompurify';
// Safe - content is sanitized before rendering
const renderTableCell = (content: string) => {
if (needsHtmlRendering(content)) {
const sanitizedContent = DOMPurify.sanitize(content);
return <div dangerouslySetInnerHTML={{ __html: sanitizedContent }} />;
}
return <span>{content}</span>;
};
// For image URLs
const renderImage = (imageUrl: string) => {
const sanitizedUrl = sanitizeImageUrl(imageUrl);
// Skip rendering if URL is invalid/unsafe
if (!sanitizedUrl) {
return null;
}
return <img src={sanitizedUrl} alt="User content" />;
};
Use appropriate logging levels to prevent debug noise from leaking into production environments. Reserve console.log() for important application events, and use console.debug() for development information that should not be visible to end users.
Example:
// Avoid: Debug information using console.log
console.log("Required fields values:", required);
// Better: Use console.debug for development information
console.debug("Required fields values:", required);
// Best: Remove debug logs before production deployment or implement
// a logging framework that controls log visibility by environment
This practice reduces noise in production logs, making important messages more visible while still allowing developers to include helpful debugging information during development.
Security controls and interactive elements must be accessible to all users to prevent unequal security access. When non-standard elements (like divs) are used for interaction, they must include proper accessibility attributes to ensure users with disabilities can access security features.
For any clickable element:
Code example (fixing the accessibility issue):
return (
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClick();
}
}}
className={`flex cursor-pointer items-center gap-1 ${className}`}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{renderIcon()}
{children}
</div>
);
This prevents security vulnerabilities for users who rely on assistive technologies by ensuring they have equal access to security-related controls and features.
When working with GitHub Actions workflows, follow these configuration best practices:
# ❌ Incorrect - may never evaluate as expected
if: ${{ inputs.enable-docker-cache == true }}
# ✅ Correct - properly compares string values
if: ${{ inputs.enable-docker-cache == 'true' }}
# ❌ Insecure - may pull unexpected updates
uses: actions/checkout@v4
# ✅ Secure - pins to specific commit
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Input naming consistency: Maintain consistent input naming across workflow triggers. Ensure variables referenced in workflows match the input names defined in workflow_call and workflow_dispatch events to avoid undefined values.
Dynamic identifiers: Include both run ID and attempt ID in dynamically generated values like branch names to ensure uniqueness across workflow reruns:
# ✅ Better uniqueness for branches created in workflows
branch: 'chore/openapi-sync-${{ github.run_id }}-${{ github.run_attempt }}'
These practices improve security, reliability, and maintainability of workflow configurations.
Ensure configuration documentation is comprehensive, clear and actionable for developers. This includes:
# Good example: Explicitly documenting all behaviors
- alwaysApply: true # Always include the rule, regardless of file context
- alwaysApply: false # Only include if globs exist AND match file context
- alwaysApply: undefined # Default: include if no globs exist OR globs exist and match
Configuration is stored in ~/.continue directory (or %USERPROFILE%\.continue on Windows)
<Tab title="YAML">
// YAML configuration example
</Tab>
<Tab title="JSON">
// JSON configuration example
</Tab>
Proper configuration documentation reduces developer confusion, prevents misconfigurations, and simplifies troubleshooting.
Always use the latest stable versions of dependencies in configuration files like Cargo.toml, and avoid deprecated or unmaintained packages. Outdated dependencies can introduce security vulnerabilities, compatibility issues, and technical debt.
When reviewing dependency changes:
Example of problematic dependency management:
# Outdated - current version is 0.30
opentelemetry = "0.27"
# Deprecated package
serde_yaml = "0.9"
# Outdated - current version is 0.30
jsonschema = "0.18"
Make dependency version reviews a standard part of configuration file changes to maintain a healthy and secure codebase.
Authentication flows should be designed to provide a seamless user experience while maintaining security standards. Avoid implementing temporary workarounds that require users to perform multiple steps, quit and restart applications, or follow complex sequences to authenticate successfully.
When designing OAuth or other authentication mechanisms, especially in CLI or no-browser environments, ensure the flow can be completed in a single session without requiring application restarts or complex user interactions. Poor authentication UX often leads to user frustration and may encourage insecure workarounds.
Example of what to avoid:
if (
settings.merged.selectedAuthType === AuthType.LOGIN_WITH_GOOGLE &&
config.getNoBrowser()
) {
// This requires users to: select auth type, quit, restart app
await getOauthClient(settings.merged.selectedAuthType, config);
}
Instead, design authentication flows that can handle the complete process in one session, with clear user guidance and fallback options that don’t compromise security or require application restarts.
Ensure all localization strings maintain consistent formatting patterns within each locale file. This includes:
Terminal punctuation: All similar messages should consistently end with appropriate punctuation marks for the locale (periods in English/French, “।” in Hindi, etc.).
Locale-specific punctuation: Use the correct width/style of punctuation marks for each language (e.g., full-width colons “:” in Chinese and Japanese, not ASCII colons “:”).
Variable interpolation syntax: Maintain consistent variable placeholder syntax. Use double curly braces for all variables: {{variableName}} not {variableName}.
Example (incorrect):
{
"errors": {
"invalidApiKey": "Invalid API key. Please check your API key configuration.",
"apiKeyRequired": "An API key is required for this embedder",
"vectorDimensionMismatch": "Failed to update vector index. Details: {errorMessage}"
}
}
Example (correct):
{
"errors": {
"invalidApiKey": "Invalid API key. Please check your API key configuration.",
"apiKeyRequired": "An API key is required for this embedder.",
"vectorDimensionMismatch": "Failed to update vector index. Details: {{errorMessage}}"
}
}
Consistent formatting makes localization files more maintainable and ensures a uniform appearance throughout the application.
When catching and re-throwing errors, always preserve the original error context using the cause option of the Error constructor. This maintains the complete error chain for debugging and ensures no critical information is lost when translating errors between layers.
Instead of:
try {
await deletePoints(filePaths)
} catch (error) {
throw new Error(`Failed to delete points: ${error.message}`)
}
Use:
try {
await deletePoints(filePaths)
} catch (error) {
throw new Error(
`Failed to delete points: ${error instanceof Error ? error.message : String(error)}`,
{ cause: error }
)
}
This practice:
When handling errors across system boundaries (e.g., API calls, file operations), this becomes especially important as it helps track down issues through multiple abstraction layers.
Use specific, descriptive parameter names for API resources rather than generic identifiers. Parameter names should clearly indicate the resource type they refer to by using namespaced identifiers (e.g., userId instead of id). This improves API readability, reduces ambiguity in code, and prevents confusion when multiple resource types are used in the same context.
When designing API endpoints:
credentialId, workflowId)For example, instead of:
# In users parameter schema
name: id
Use:
# In users parameter schema
name: userId
This practice is especially important in OpenAPI specifications where parameter names directly impact client implementations. Changing parameter names after an API is published can break clients and require comprehensive updates across endpoint definitions, routes, controllers, and documentation.
Identify and prevent race conditions in asynchronous operations, especially when operations depend on each other’s completion state. Race conditions occur when the timing or order of async operations affects program correctness, often leading to intermittent failures that are difficult to debug.
Common scenarios include:
Instead of using arbitrary timeouts, use proper synchronization mechanisms like condition waiting, promises, or explicit state checking.
Example from the codebase:
// Problem: Race condition - command returns before UI is ready
await vscode.commands.executeCommand("cline.focusChatInput")
// This executes too early, before focus is actually set
visibleWebview?.controller.fixWithCline(...)
// Better: Use proper waiting mechanism
await vscode.commands.executeCommand("cline.focusChatInput")
await pWaitFor(() => webviewIsFocused()) // Wait for actual condition
visibleWebview?.controller.fixWithCline(...)
Always consider: What assumptions am I making about timing? Could this operation execute before its dependencies are ready? What happens if this code runs concurrently with itself?
Always include all referenced variables in React hook dependency arrays (useEffect, useCallback, useMemo). Missing or incorrect dependencies can lead to stale closures, unexpected behavior, and difficult-to-diagnose bugs.
When using hooks with dependency arrays:
// ❌ Incorrect: Missing dependency
const handleSubmit = useCallback(() => {
if (currentState.isValid) {
submitData(formData);
}
}, [formData]); // currentState is missing
// ✅ Correct: Complete dependency array
const handleSubmit = useCallback(() => {
if (currentState.isValid) {
submitData(formData);
}
}, [formData, currentState]);
// ✅ Correct: useEffect with event listener cleanup
useEffect(() => {
// Only add the listener if condition is met
if (toolCallState?.status === "generated") {
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}
}, [toolCallState, handleKeyDown]);
Consider using the ESLint plugin ‘eslint-plugin-react-hooks’ with the exhaustive-deps rule to automatically detect missing dependencies.
Identify and extract shared functionality between classes into reusable components. Code duplication increases maintenance burden and risk of inconsistent behavior when changes are needed.
Use these approaches to eliminate duplication:
Example of problematic duplication:
// In NextEditService
fun triggerNextEdit() {
// Almost identical code to triggerCompletion() in AutocompleteService
// with minor differences
}
// In AutocompleteService
fun triggerCompletion() {
// Almost identical code to triggerNextEdit() in NextEditService
// with minor differences
}
Better approach:
// In a shared abstract base class or utility class
abstract class EditServiceBase {
protected fun triggerEdit(editType: String, parameters: Map<String, Any>) {
// Common implementation
}
}
// In concrete implementations
class NextEditService : EditServiceBase() {
fun triggerNextEdit() {
triggerEdit("nextEdit", specificParameters)
}
}
class AutocompleteService : EditServiceBase() {
fun triggerCompletion() {
triggerEdit("completion", specificParameters)
}
}
For data types with associated utilities, follow the pattern demonstrated in RangeInFileWithContents where data and its manipulation methods are encapsulated together.
Ensure configuration documentation clearly distinguishes between deployment contexts and uses consistent terminology throughout. When documenting configuration procedures, explicitly specify the target deployment type (Langflow Desktop vs OSS) and platform (macOS vs Windows) to avoid user confusion.
Key requirements:
~/.langflow) for cross-platform clarityExample of improved configuration documentation:
## Set environment variables for Langflow Desktop
### macOS
Langflow Desktop for macOS cannot automatically use variables set in your terminal, such as those in `.zshrc` or `.bash_profile`, when launched from the macOS GUI.
To make environment variables available to GUI apps on macOS, you need to use `launchctl` with a `plist` file:
1. Create the `LaunchAgents` directory if it doesn't exist:
```bash
mkdir -p ~/Library/LaunchAgents
Langflow Desktop for Windows cannot automatically use variables set in your terminal, such as those defined with set in cmd or $env:VAR=... in PowerShell, when launched from the Windows GUI.
To make environment variables available to the Langflow Desktop app, you must set them at the user or system level using the System Properties interface or the Terminal.
This approach prevents user confusion about which instructions apply to their specific setup and ensures consistent experience across different deployment scenarios.
---
## Maintain configuration consistency
<!-- source: browser-use/browser-use | topic: Configurations | language: Other | updated: 2025-07-09 -->
When modifying configuration settings, especially environment variables, ensure changes are consistent with existing codebase usage patterns and maintain backward compatibility. Before changing configuration names or values, audit the codebase to understand current usage and dependencies.
For environment variables, check how they are referenced throughout the application, including tests, documentation, and third-party integrations. Consider that different libraries may expect different variable names for the same functionality.
Example from Azure OpenAI configuration:
```python
# Check existing usage before changing variable names
return AzureChatOpenAI(
model='gpt-4o',
api_version='2024-10-21',
azure_endpoint=os.getenv('AZURE_OPENAI_ENDPOINT', ''),
api_key=SecretStr(os.getenv('AZURE_OPENAI_KEY', '')), # Keep existing name
)
For related configuration values, ensure they are compatible with each other. For instance, when setting viewport and window sizes, account for UI chrome and ensure viewport dimensions don’t exceed window dimensions to prevent content cutoff.
Ensure all API documentation and code examples include proper authentication headers and clearly explain authentication requirements. As of Langflow v1.5, all API requests require a Langflow API key, even when AUTO_LOGIN is enabled. The only exceptions are MCP endpoints (/v1/mcp, /v1/mcp-projects, /v2/mcp) which don’t require authentication regardless of the AUTO_LOGIN setting.
All curl examples, code snippets, and API documentation should include the x-api-key header:
curl -X POST \
"http://localhost:7860/api/v1/run/FLOW_ID" \
-H "Content-Type: application/json" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-d '{"input_value": "Hello"}'
When documenting API endpoints, explicitly state authentication requirements and provide guidance on obtaining API keys. Update any legacy examples that assume no authentication is needed, and ensure consistency across all API-related documentation. This prevents user confusion and ensures examples work out of the box with current Langflow versions.
Use clear, consistent, and semantic naming patterns across your codebase to improve readability and maintainability:
// Avoid providerDefinedToolFactory() jsonParser()
2. **Use descriptive names for generics** rather than single letters:
```typescript
// Good
interface Provider<LANGUAGE extends string, CONTEXT extends string>
// Avoid
interface Provider<L extends string, C extends string>
// Avoid duration: number concurrency: number
5. **Use standard terminology** in field names (e.g., `mediaType` for IANA media types)
6. **Ensure test naming matches implementation** to avoid confusion and maintenance issues
Following these conventions makes your code more self-documenting, easier to understand, and reduces the cognitive load for developers reading and maintaining the code.
---
## Type-safe null handling
<!-- source: vercel/ai | topic: Null Handling | language: TypeScript | updated: 2025-07-08 -->
Use TypeScript's type system and modern JavaScript features to prevent null reference errors.
**TypeScript type safety:**
- Prefer `never` over `undefined` for properties that shouldn't have values
- Use `unknown` instead of `any` when working with data of uncertain structure
- Validate data with zod schemas instead of using type assertions (`as`)
- Use proper type narrowing with type guards
**Modern JavaScript null checks:**
- Use nullish coalescing (`??`) for default values:
```typescript
// Instead of this:
const citations = response.message.citations ? response.message.citations : [];
// Do this:
const citations = response.message.citations ?? [];
?.) for accessing properties on potentially undefined objects:
```typescript
// Instead of this:
const contentType = requestClone.headers.get(‘content-type’) || ‘’;
if (contentType.startsWith(‘multipart/form-data’)) { /…/ }// Do this: const contentType = requestClone.headers.get(‘content-type’); if (contentType?.startsWith(‘multipart/form-data’)) { /…/ }
Following these patterns leads to more robust, self-documenting code and fewer runtime errors from unexpected null/undefined values.
---
## Verify AI model capabilities
<!-- source: vercel/ai | topic: AI | language: Other | updated: 2025-07-08 -->
Always verify and accurately document AI model capabilities, supported formats, and limitations before implementation. Use consistent terminology (e.g., "multi-modal" instead of "multimodal") and validate model features against official documentation sources. When documenting AI functionalities:
1. Be explicit about supported features and limitations
2. Link to official documentation when describing specific capabilities
3. Don't assume cross-functionality unless confirmed
4. Use clear, concise language when describing input formats and parameters
Example:
```typescript
// GOOD: Accurate, verified documentation with specific capabilities
// Groq's multi-modal models like `meta-llama/llama-4-scout-17b-16e-instruct`
// support image inputs via URLs or base64-encoded data
// Source: https://groq.com/docs/models/llama-4-scout
// BAD: Unverified or inaccurate information
// OpenAI's o4 model is available (incorrect - only o4-mini is publicly available)
// Assuming a model supports certain parameter formats without verification
Maintaining accurate documentation saves development time, prevents integration errors, and helps teams properly utilize AI capabilities within their applications.
Names should be semantically meaningful and consistent across related concepts in the codebase. This applies to variables, functions, components, and types. When naming:
Example of poor naming consistency:
// Inconsistent naming pattern
interface User {
customer_id: string; // Uses _id suffix
group: string; // Missing _id suffix
}
function enableStreaminOption() {} // Misspelled, unclear verb
Improved version:
// Consistent naming pattern
interface User {
customerId: string; // Consistent camelCase
groupId: string; // Consistent naming pattern
}
function createStreamingOption() {} // Clear verb, correct spelling
This helps maintain code readability and reduces cognitive load when working across different parts of the codebase.
Use camelCase consistently for all property names, method names, and configuration options, even when interacting with external APIs that use different conventions (like snake_case). This maintains codebase consistency and makes interfaces more predictable for developers.
When encountering inconsistencies:
// INCORRECT: Using external snake_case convention in internal code
const options = {
file_format: 'mp3',
timestamp_granularities: ['word']
};
// CORRECT: Maintaining camelCase in internal code
const options = {
fileFormat: 'mp3',
timestampGranularities: ['word']
};
// When sending to external API, transform as needed
sendToExternalApi({
file_format: options.fileFormat,
timestamp_granularities: options.timestampGranularities
});
This approach creates a clear separation between internal naming conventions and external API requirements, leading to more consistent and maintainable code.
Documentation should be formatted appropriately for its intended rendering context and ensure discoverability. Consider how documentation files will be displayed in different environments (GitHub, websites, etc.) and choose appropriate file formats and structures.
Key practices:
.md instead of .mdx unless you specifically need MDX features and have a rendering environment that supports themcontributing/) to keep main documentation conciseExample:
<!-- Good practice: Using appropriate extension and avoiding formatting that breaks rendering -->
# Contributing Guide
## Overview
Brief introduction to contribution process
## Detailed Guides
For more information, see:
- [How to create a codemod](./contributing/how-to-create-a-codemod.md)
- [Package structure](./contributing/packages.md)
## Changelog Format
When creating a changeset, avoid using headings at the beginning of the message:
feat(embedding-model-v2): add providerOptions
By considering the rendering context, you ensure documentation remains accessible and displays correctly across different platforms.
Use React hooks only when you need reactivity and component re-rendering. For accessing instantaneous values or one-time data retrieval, prefer plain functions to avoid unnecessary re-renders and improve performance.
When you only need current state values without subscribing to changes, use direct selector calls instead of hooks:
// ❌ Avoid - causes unnecessary re-renders for instantaneous values
export const useMainInterfaceAnalytics = (): MainInterfaceAnalyticsData => {
const session = useSessionStore(sessionSelectors.currentSession);
// ... other hook calls
}
// ✅ Prefer - direct access for one-time values
export const getMainInterfaceAnalytics = (): MainInterfaceAnalyticsData => {
const session = sessionSelectors.currentSession(getSessionStoreState());
// ... direct selector calls
}
Consider component lifecycle when deciding state placement. If components unmount and remount frequently, evaluate whether state should persist in a global store or reset with component lifecycle.
Configuration values should be externalized to environment variables rather than hardcoded in the source code. This improves flexibility, security, and deployment across different environments.
Hardcoded configuration values make applications inflexible and difficult to deploy across different environments. Instead, use environment variables with sensible defaults.
Example of the improvement:
# Bad: Hardcoded configuration
self.client = openai.OpenAI(
api_key="ollama",
base_url="http://localhost:11434"
)
# Good: Environment-configurable
self.client = openai.OpenAI(
api_key=os.getenv("OLLAMA_API_KEY", "ollama"),
base_url=os.getenv("OLLAMA_HOST", "http://localhost:11434")
)
This approach allows the same code to work in development, testing, and production environments by simply changing environment variables, without requiring code modifications or rebuilds.
Adhere to established naming conventions consistently throughout the codebase, prioritizing official documentation standards when available. Use appropriate case conventions (ALL_CAPS for constants, descriptive names for variables) and maintain consistency with external API standards.
When naming conflicts arise between internal consistency and official documentation, prefer the official documentation approach. For constants, use ALL_CAPS to clearly indicate their global scope and immutable nature.
Examples:
# Good: Constant with proper naming
MODEL_PARAMETERS = ModelParameters(...)
# Good: API key following official documentation
API_KEY = os.getenv("GEMINI_API_KEY") # Following Google's official docs
# Avoid: Inconsistent constant naming
model_parameters = ModelParameters(...)
# Avoid: Internal naming that conflicts with official docs
API_KEY = os.getenv("GOOGLE_API_KEY") # When official docs specify GEMINI_API_KEY
This approach enhances code readability, reduces confusion for new team members, and ensures compatibility with external documentation and examples.
Implement comprehensive error handling to prevent crashes and aid debugging. This includes:
// Before
const data = JSON.parse(message.text || "{}");
// After
let data;
try {
data = JSON.parse(message.text || "{}");
} catch (error) {
console.error("Failed to parse message data:", error);
data = {}; // Provide fallback value
}
class ErrorBoundary extends Component<ErrorProps, ErrorState> {
constructor(props: ErrorProps) {
super(props);
this.state = {};
}
static getDerivedStateFromError(error: unknown) {
return {
error: error instanceof Error ? (error.stack ?? error.message) : `${error}`,
};
}
// Add this method to capture additional context
componentDidCatch(error: Error, info: React.ErrorInfo) {
// Log to monitoring system with context
logErrorToService({
error,
componentStack: info.componentStack,
timestamp: new Date().toISOString(),
additionalContext: this.props.contextData
});
}
render() {
if (this.state.error) {
return <ErrorDisplay error={this.state.error} />;
}
return this.props.children;
}
}
This approach ensures your application degrades gracefully when errors occur while providing the information needed to fix underlying issues.
When implementing functionality, evaluate whether simpler algorithmic approaches or more appropriate data structures can achieve the same result with less complexity. Look for opportunities to eliminate unnecessary conditional branching, use built-in operations for common tasks, and leverage established patterns like regex for pattern matching.
Common simplifications include:
list({*existing_items, *new_items})scroll_amount = int(window_height * (params.num_pages or 1))["deepseek-reasoner", "deepseek-r1", "gemma.*-it"]Before implementing complex logic, ask: “Is there a simpler way to achieve this using standard algorithms, data structures, or library functions?” This approach typically results in more maintainable, readable, and efficient code.
When implementing features that may run concurrently, always ensure thread safety using appropriate synchronization mechanisms:
# Good: Using contextvars-based solutions for thread isolation
ctx = baggage.set_baggage(...) # Uses contextvars internally for thread safety
# Good: Adding locks to prevent race conditions
_lock: Lock = threading.Lock()
def singleton_method(self):
with self._lock:
# Access or modify shared state safely
# Better: Simple thread-based timeout pattern
thread = threading.Thread(target=target, daemon=True)
thread.start()
thread.join(timeout=timeout)
if thread.is_alive():
# Handle timeout case
These patterns help prevent hard-to-debug race conditions, ensure consistent behavior in concurrent environments, and make code more maintainable by clearly indicating thread safety considerations.
Maintain consistent formatting and syntax across all documentation and code examples to improve readability and functionality. Follow established style guides and ensure uniformity in presentation.
For documentation formatting, use consistent patterns for optional steps and procedures. For example, format optional steps as “Optional:” rather than “(Optional)” following Google’s style guide:
3. Optional: Install pre-commit hooks to help keep your changes clean and well-formatted.
For code examples, standardize quote usage throughout all examples. Use double quotes for headers and variables that need expansion:
curl -X POST \
"http://localhost:7860/api/v1/webhook/YOUR_FLOW_ID" \
-H "Content-Type: application/json" \
-H "x-api-key: $LANGFLOW_API_KEY" \
This ensures both visual consistency and functional correctness, as single quotes prevent variable expansion while double quotes allow it.
Always validate that environment bindings exist and are of the expected type before using them, and ensure external dependencies are properly configured in build scripts. Runtime binding validation prevents cryptic errors when bindings are missing or misconfigured, while proper build configuration prevents dynamic import issues in serverless environments.
For runtime validation, check both existence and type:
const bindingValue = env[binding as keyof typeof env] as unknown;
// Ensure we have a binding of some sort
if (bindingValue == null || typeof bindingValue !== "object") {
console.error(
`Could not find binding for ${binding}. Did you update your wrangler configuration?`
);
return new Response("Invalid binding", { status: 500 });
}
// Ensure that the binding is to a DurableObject
if (bindingValue.toString() !== "[object DurableObjectNamespace]") {
return new Response("Invalid binding", { status: 500 });
}
For build configuration, include external packages in your build scripts and use top-level imports instead of dynamic imports:
// In build.ts - add external packages
external: ["cloudflare:email", "other-external-packages"]
// In code - use top-level imports
import { createMimeMessage } from "mimetext";
import { EmailMessage } from "cloudflare:email";
Configuration documentation should include all necessary constraints and limitations while avoiding redundant information that’s already documented elsewhere. Always document critical constraints that could cause runtime issues, such as resource conflicts or usage limitations. Remove duplicate explanations that repeat information available in other parts of the documentation to maintain clarity and reduce verbosity.
Example of good constraint documentation:
# Create browser config with user_data_dir
config = BrowserConfig(
headless=False,
user_data_dir="/path/to/your/user_data_dir"
)
The browser will use this directory to store all profile data, which will persist between browser sessions. Only one browser at a time can be running with this user_data_dir, make sure to close any browsers using it before starting browser-use.
Avoid duplicating parameter explanations that are already covered in function signatures or other documentation sections.
Prefer async/await syntax over promise chains or callback patterns when working with asynchronous operations. This improves code readability, makes error handling more straightforward, and maintains consistency across the codebase.
Example (converting from promise chain to async/await):
// Instead of this:
ideMessenger
.request("controlPlane/getFreeTrialStatus", undefined)
.then(response => {
// handle response
})
.catch(error => {
// handle error
});
// Prefer this:
async function getFreeTrialStatus() {
try {
const response = await ideMessenger.request("controlPlane/getFreeTrialStatus", undefined);
// handle response
} catch (error) {
// handle error
}
}
This pattern not only enhances readability but also helps avoid the “callback hell” that can occur with chained promises in complex asynchronous operations. Code written with async/await tends to follow a more natural top-to-bottom execution flow that’s easier to reason about when dealing with concurrent operations.
Always use completely fictional personal information in sample files, documentation, test data, and code examples to prevent privacy violations and unintentional exposure of real people’s data. Real names, email addresses, phone numbers, and social media profiles should never appear in sample data as they can link to actual individuals and create privacy risks.
Example of what to avoid:
Emily J. Wilson
Email: emilyjwilson@example.com
Phone: 555-789-0123
LinkedIn: linkedin.com/in/emilyjwilson
Instead, use clearly fictional data:
Jane Doe
Email: jane.doe@example.com
Phone: 555-000-0000
LinkedIn: linkedin.com/in/janedoe-sample
This practice protects individual privacy and prevents potential legal or ethical issues that could arise from using real personal information without consent.
Always use cryptographically secure random number generation for security-sensitive operations such as generating session IDs, authentication tokens, or unique identifiers. Standard random number generators like Math.random() are designed for statistical randomness, not security, making them vulnerable to prediction and exploitation by attackers.
// Insecure - using Math.random() for session IDs:
const sessionId = `roo-${Date.now()}-${Math.random().toString(36).substring(7)}`;
// Secure - using cryptographic randomness:
import crypto from 'crypto';
// In Node.js:
const sessionId = `roo-${Date.now()}-${crypto.randomBytes(16).toString('hex')}`;
// OR
const sessionId = `roo-${Date.now()}-${crypto.randomUUID()}`;
For browser environments, use the Web Crypto API:
// Browser environment:
const array = new Uint8Array(16);
window.crypto.getRandomValues(array);
const sessionId = `roo-${Date.now()}-${Array.from(array).map(b => b.toString(16).padStart(2, '0')).join('')}`;
Predictable randomness can lead to session hijacking, token guessing, and other security vulnerabilities that may compromise user data or system integrity.
Maintain consistent and clean code formatting to improve readability and maintainability. Follow these guidelines:
// ❌ Bad
className="gap 1.5 flex-row"
className={`${toolsSupported ? "md:flex" : "int:flex"} hover:underline"`}
// ✅ Good
className="gap-1.5 flex-row"
className={`hover:underline ${toolsSupported ? "md:flex" : ""}`}
// ❌ Bad
) : item.message.role === "tool" ? null : item.message.role === // comment here
// ✅ Good
// Comment above the expression
) : item.message.role === "tool" ? null : item.message.role === "assistant"
These rules help maintain code consistency, improve readability, and make the codebase easier to maintain and refactor.
Documentation should include concrete, executable code examples rather than vague instructions. Make your examples copy-paste ready with all necessary context and dependencies. When documenting features or APIs, show exactly how they should be used in practice.
For example, instead of just stating:
// Don't do this
// You can pass provider options as an argument
Provide a complete, executable example:
// Do this
const result = await embed({
model: cohere.embedding('embed-english-v3.0'),
input: 'Hello world',
providerOptions: {
cohere: {
inputType: 'search_query'
}
}
});
For pre-release or alpha software, clearly state limitations and expectations (e.g., “not for production use”, “subject to breaking changes”). Always aim to create documentation that developers can immediately implement without needing to figure out missing pieces.
When maintaining CI/CD pipelines, regularly audit and remove runtime versions that are no longer supported by your project’s dependencies or cause build failures. This prevents pipeline instability and reduces maintenance overhead.
Unsupported versions should be removed from all workflow matrices consistently across test, integration, and end-to-end testing jobs to maintain pipeline reliability.
Example:
strategy:
matrix:
# Remove 18.x due to dependency compatibility issues
node-version: [20.x, 22.x, 24.x]
This practice ensures that CI resources are focused on supported runtime environments and prevents false negatives from incompatible version combinations. When removing versions, document the reasoning (e.g., “dependency requires Node 20+”) to help future maintainers understand the decision.
Tests tightly coupled to implementation details break easily when the implementation changes, creating maintenance burden and reducing test reliability. Write tests that validate behavior rather than specific implementation details.
To avoid implementation coupling:
// GOOD
import { DEFAULT_GIT_DIFF_LINE_LIMIT } from "./viewDiff";
test("viewDiff should truncate diffs exceeding line limit", async () => {
const largeInput = Array(DEFAULT_GIT_DIFF_LINE_LIMIT + 1).fill("test line");
// ...
});
// BAD
test("viewDiff should truncate diffs exceeding line limit", async () => {
const DEFAULT_GIT_DIFF_LINE_LIMIT = 5000; // Duplicated constant
// Test will break if implementation changes the limit
// ...
});
// GOOD
test("should use the default TTL value", () => {
const anthropic = new Anthropic({/* config */});
const defaultTtl = anthropic.getDefaultTtl(); // Get actual implementation value
const result = anthropic.convertMessages(messages);
expect(result[0].content[0].cache_control.ttl).toBe(defaultTtl);
});
// BAD
test("should use default TTL when not specified", () => {
// Assumes '5m' is the default without verification
expect(result.content[0].cache_control.ttl).toBe("5m");
});
// GOOD - Tests behavior without assuming structure
test("should contain expected rule names", () => {
const applicableRules = getApplicableRules();
expect(getRuleNames(applicableRules)).toContain("Global Rule");
});
// BAD - Tightly coupled to structure
test("should contain expected rule names", () => {
const applicableRules = getApplicableRules();
expect(applicableRules.map(r => r.rule.name)).toContain("Global Rule");
});
When mocking, verify the right parameters are passed rather than just counting calls. This ensures tests remain valid even when implementation details change.
When documenting features that involve sensitive data, authentication, or privileged operations, explicitly state the security implications and use appropriate warning levels to ensure users understand potential risks.
This includes:
:::warning instead of :::important when documenting features that could expose sensitive information like API keysExample from API key documentation:
:::warning
An API key represents the user who created it. If you create a key as a superuser, then that key will have superuser privileges.
Anyone who has that key can authorize superuser actions through the Langflow API, including user management and flow management.
:::
This practice helps users make informed security decisions and prevents inadvertent exposure of sensitive information through better awareness of security implications.
When working with timeouts and asynchronous operations that affect shared state, clear timeouts at the beginning of event handlers or user interactions to prevent race conditions. This defensive approach ensures that competing operations (like auto-approval timers and manual user actions) don’t conflict.
Always implement shared cancellation mechanisms when multiple components or functions interact with the same asynchronous process:
// GOOD: Clear timeouts at the beginning of handlers
function handleSendMessage(text, images) {
// Clear auto-approval timeout FIRST to prevent race conditions
if (autoApproveTimeoutRef.current) {
clearTimeout(autoApproveTimeoutRef.current);
autoApproveTimeoutRef.current = null;
}
// Now process the message safely
if (messagesRef.current.length === 0) {
vscode.postMessage({ type: "newTask", text, images });
} else {
// Other processing...
}
}
// BAD: Clearing timeouts inside conditional blocks can lead to race conditions
function handleSendMessage(text, images) {
if (messagesRef.current.length === 0) {
vscode.postMessage({ type: "newTask", text, images });
} else if (clineAskRef.current === "followup") {
// Timeout might fire before reaching this point!
if (autoApproveTimeoutRef.current) {
clearTimeout(autoApproveTimeoutRef.current);
}
// Process message...
}
}
For components with interdependent timers, consider using a shared state or context to coordinate cancellation across component boundaries.
Always use relative links instead of absolute links in documentation files to enable proper broken link detection and ensure compatibility with documentation generators like MkDocs.
Absolute links prevent documentation tools from detecting broken links and can cause navigation issues. MkDocs specifically does not support absolute links by default and will generate warnings for unrecognized absolute paths.
Problematic (absolute links):
- [Building AI Agents with DSPy](/tutorials/customer_service_agent/)
- [Set Up Observability](../tutorials/observability/#tracing)
Correct (relative links):
- [Building AI Agents with DSPy](../customer_service_agent/index.ipynb)
- [Set Up Observability](../tutorials/observability/index.md#tracing)
When linking to sections within other pages, include the full file path with index.md to help MkDocs understand the relative link structure. This prevents warnings like “contains an unrecognized relative link” and ensures proper link resolution in the generated documentation.
Establish and follow consistent naming conventions for similar types of elements throughout the codebase and documentation. When multiple instances of the same type of element exist, ensure they follow the same naming pattern to avoid confusion and improve maintainability.
For documentation placeholders and variables, standardize on a single format (e.g., $VARIABLE_NAME vs VARIABLE_NAME) and apply it consistently across all documentation. For section headers and labels, ensure the naming accurately reflects the scope of content - use plural forms when covering multiple items and singular when covering a single concept.
Example issues to avoid:
# Bad: Inconsistent placeholder formats
--url "http://LANGFLOW_SERVER_ADDRESS/api/v1/run/FLOW_ID"
--header "x-api-key: $LANGFLOW_API_KEY"
# Good: Consistent placeholder format
--url "http://$LANGFLOW_SERVER_ADDRESS/api/v1/run/$FLOW_ID"
--header "x-api-key: $LANGFLOW_API_KEY"
# Bad: Inaccurate scope naming
## Component menu (when describing multiple menus)
# Good: Accurate scope naming
## Component menus (when describing multiple menus)
This prevents confusion for users and developers, and makes the codebase more professional and maintainable.
Identify and extract duplicate code patterns into shared utility functions to improve maintainability and reduce redundancy. When similar logic appears in multiple places, create a reusable function in a shared utility file.
Example of problematic code:
// In openai.ts
private isInsufficientQuotaError(error: any): boolean {
// Duplicate quota detection logic
}
// In openai-compatible.ts
private isInsufficientQuotaError(error: any): boolean {
// Same quota detection logic repeated
}
Better approach:
// In shared/quota-utils.ts
export function isInsufficientQuotaError(error: any): boolean {
// Centralized quota detection logic
}
// In both files:
import { isInsufficientQuotaError } from '../shared/quota-utils';
Key guidelines:
This improves code maintainability by:
Always ensure configuration files, especially JSON files, have unique keys. Duplicate keys can cause unpredictable behavior as the last occurrence of a key will overwrite previous values, potentially leading to runtime errors or inconsistent application behavior.
When adding new configuration:
Example of problematic code:
{
"codeIndex": {
"setting1": "value1"
},
// Other settings...
"codeIndex": {
"setting2": "value2"
}
}
Correct approach:
{
"codeIndex": {
"setting1": "value1",
"setting2": "value2"
}
// Other settings...
}
This is especially critical in localization files and application configuration where duplicate keys can lead to missing translations or incorrect settings being applied.
When modifying configuration files (package.json, tsconfig.json, etc.), document the reasoning behind significant changes and verify they don’t introduce unexpected side effects. This is especially important for changes affecting dependencies and build processes.
For dependency management:
For build configurations:
Example:
// package.json
{
"dependencies": {
// Fixed version for critical dependencies with compatibility requirements
"prettier": "3.5.3",
"prettier-plugin-svelte": "3.2.7",
// Regular dependency for internal tools (not peer/dev)
"zod": "3.23.8"
}
}
// tsconfig.json
{
"compilerOptions": {
// Best practice for bundler targets (enables better dead code removal)
"module": "ESNext",
// Other settings...
}
}
When making these changes, document your reasoning in commit messages or inline comments to provide context for other developers.
Always validate configuration parameters and environment variables at initialization time, providing clear error messages for missing or invalid values. This helps catch configuration issues early and makes debugging easier.
Key practices:
Example:
def __init__(self, api_key: Optional[str] = None):
# Check required env vars early
if not api_key and "REQUIRED_API_KEY" not in os.environ:
raise ValueError(
"API key must be provided either through initialization parameter "
"or REQUIRED_API_KEY environment variable"
)
# Respect parameter hierarchy
self.api_key = api_key or os.environ["REQUIRED_API_KEY"]
# Only import optional dependencies if configured
if self.api_key:
try:
from optional_package import OptionalClient
self.client = OptionalClient(self.api_key)
except ImportError:
raise ImportError(
"Optional package is required when using this feature. "
"Install it with: pip install optional_package"
)
Ensure API documentation includes all required networking components and uses proper syntax for shell commands. API examples must include authentication headers, use correct variable expansion syntax, and clearly state network configuration assumptions.
Key requirements:
x-api-key)Example of proper curl documentation:
curl -X POST "http://localhost:7860/api/v1/run/$FLOW_ID" \
-H "Content-Type: application/json" \
-H "x-api-key: $LANGFLOW_API_KEY" \
-d '{
"input_value": "message",
"input_type": "chat",
"output_type": "chat"
}'
This ensures developers can successfully integrate with network services without encountering authentication failures or variable expansion issues that would prevent proper API communication.
Console logs should not appear in production code, especially debug statements that can expose sensitive information or clutter output. When error logging is necessary, log detailed information internally while presenting sanitized messages to users.
Remove debug console.log statements before merging to production. For legitimate error handling, use proper error logging that separates internal details from user-facing messages.
Example of proper error logging:
} catch (err) {
// Log full error details internally for debugging
console.error(`Error during Claude Code execution:`, err)
// Show sanitized message to user
throw new Error(`Claude Code process failed.${errorOutput ? ` Error: ${errorOutput}` : ""}`)
}
Be particularly strict with files that handle sensitive data or user interactions. Consider adding code comments or linting rules to prevent console logs from being reintroduced in critical files.
Before adding manual configuration entries, verify that the tool doesn’t already provide the desired behavior automatically. Document why the override is necessary and what specific problem it solves.
Many development tools have intelligent defaults and auto-discovery features. Adding unnecessary configurations can create maintenance overhead and potential conflicts.
When proposing configuration changes:
Example from VS Code keybindings:
{
"command": "editor.action.inlineSuggest.commit",
"key": "tab",
"when": "inlineSuggestionVisible && editorTextFocus && !editorTabMovesFocus && !inSnippetMode && !suggestWidgetVisible"
}
Instead of complex conditions, first verify if the desired behavior can be achieved through simpler means or if the tool already supports it in certain contexts.
Reduce test code duplication by organizing common setup logic and grouping related tests appropriately. Move repeated setup code into beforeEach hooks and use describe blocks to group tests that share similar setup or test the same feature area.
When tests have repeated setup code, extract it to beforeEach to improve maintainability. For feature-specific tests, group them in dedicated describe blocks with their own setup:
describe("AutocompleteProvider whitespace handling", () => {
let mockContext: any
let mockProvider: any
let provideInlineCompletionItems: any
beforeEach(() => {
vi.clearAllMocks()
mockContext = {
subscriptions: [],
}
// Common setup for all whitespace tests
vi.mocked(ContextProxy.instance.getGlobalState).mockReturnValue({
autocomplete: true,
})
})
// Individual tests here...
})
For test utilities that need global access, provide clear documentation explaining their purpose and scope, especially when exposing APIs for testing convenience.
Avoid storing simple configuration data in separate JSON files. Instead, define configuration as Python dictionaries directly within the relevant modules. This approach reduces file overhead, improves maintainability, and keeps related code together.
When configuration is static and doesn’t require external modification, inline dictionaries are preferred over separate JSON files. This pattern should be used for initialization parameters, default settings, and other module-specific configuration data.
Example transformation:
# Instead of loading from initialize_params.json
# with open('initialize_params.json') as f:
# config = json.load(f)
# Define configuration directly in the module
INITIALIZE_PARAMS = {
"processId": None,
"clientInfo": {
"name": "solidlsp",
"version": "1.0.0"
},
"capabilities": {
"textDocument": {
"completion": {"completionItem": {"snippetSupport": True}}
}
}
}
Reserve external JSON files for configuration that needs to be modified by users or varies between environments.
When constructing templates or dynamic content that will be parsed, always implement robust escaping mechanisms to prevent injection vulnerabilities. Avoid using delimiters in template strings that might appear in the content itself, as this could break formatting or enable code injection attacks.
For example, instead of:
const template = "```{{{languageShorthand}}}\n{{{userExcerpts}}}```";
Consider using:
This practice is critical for preventing cross-site scripting (XSS), SQL injection, command injection, and other security vulnerabilities that occur when user input is improperly handled in templates or dynamic content.
Ensure component usage in templates matches registered components. Vue components must be referenced in templates by either their kebab-case equivalent or by their exact registered name.
When registering a component:
components: {
N8nIcon,
},
Use it in templates with the matching kebab-case name:
<n8n-icon v-bind="args" />
Or with the exact registered name:
<N8nIcon v-bind="args" />
Using inconsistent names like <flowstate-icon> when the component is registered as N8nIcon will cause runtime errors because Vue will not recognize the element.
This also applies to all component closing tags, which should match the opening tag. Consistent component naming helps prevent runtime errors, improves code readability, and follows Vue’s standard conventions.
Tests should be straightforward, explicit, and free from complex logic or indirection. Avoid “magic” in tests that makes them harder to understand at a glance. When designing tests:
// Prefer: const store = new ChatStore({ chats });
2. Inline test data directly rather than using complex extraction logic:
```javascript
// Avoid:
const text = content
.filter(item => item.type === 'text' && !item.thought)
.map(item => item.text)
.join('');
// Prefer:
expect(content).toMatchInlineSnapshot(`
[
{ "type": "text", "text": "Hello, World!" },
]
`);
Test one behavior per test case so they can fail independently and provide clear signals about what’s broken.
Make tests deterministic by stubbing variable elements like dates, timeouts, and IDs.
Simple tests are easier to understand, debug, and maintain, serving effectively as both verification tools and living documentation of expected behavior.
Always use React’s reactive hook patterns instead of imperative state access or manual effect management. This ensures proper component re-rendering, better performance, and cleaner code architecture.
Avoid non-reactive state access:
// ❌ Bad - non-reactive, fixed value
const config = useAgentStore.getState().currentAgentChatConfig;
const inboxMessages = useChatStore.getState().messagesMap[messageMapKey(INBOX_SESSION_ID, activeTopicId)] || [];
// ✅ Good - reactive hook usage
const config = useAgentStore(agentSelectors.currentAgentChatConfig);
const inboxMessages = useChatStore(chatSelectors.inboxActiveTopicMessages);
Use proper data fetching patterns:
// ❌ Bad - manual useEffect for data fetching
useEffect(() => {
const fetchData = async () => {
const data = await api.getData();
setData(data);
};
fetchData();
}, []);
// ✅ Good - use data fetching libraries
const { data, loading, error } = useSWR('/api/data', fetcher);
Leverage React’s built-in capabilities:
Write store selectors with proper patterns to prevent unnecessary component re-renders. Use inline selector functions that extract only the needed data, and provide custom equality comparisons for complex data types like arrays and objects.
For simple value extraction, use inline selector functions:
// ❌ Incorrect - causes re-renders when unrelated store data changes
const config = useAgentStore(agentChatConfigSelectors.currentChatConfig);
const enableCompressHistory = config.enableCompressHistory;
// ✅ Correct - only re-renders when enableCompressHistory changes
const enableCompressHistory = useAgentStore(
s => agentChatConfigSelectors.currentChatConfig(s).enableCompressHistory
);
For arrays and objects, use equality comparisons to prevent re-renders on reference changes:
import isEqual from 'fast-deep-equal';
// ✅ Correct - prevents re-renders when array contents are the same
const remoteModels = useUserStore(
modelProviderSelectors.remoteProviderModelCards(provider),
isEqual
);
This prevents performance issues where components re-render unnecessarily when unrelated store data changes, improving overall application responsiveness.
Credentials, passwords, API tokens, and database connection strings must never be committed to version control in any form, even in configuration files or Kubernetes manifests. This practice exposes sensitive information to anyone with repository access and creates security vulnerabilities.
Instead:
Example - Replace hardcoded credentials:
# INSECURE - Don't do this
MONGODB_URI: "mongodb+srv://akaneai420:ilovehentai123@cluster0.jwyab3g.mongodb.net/?retryWrites=true"
LOGIN_PASSWORD: password
# SECURE - Do this instead
MONGODB_URI: "${MONGODB_URI}"
LOGIN_PASSWORD: ${LOGIN_PASSWORD}
For Kubernetes, use secrets management solutions rather than committing stringData values directly. When committing example configurations, always use placeholder values that make it clear a real value needs to be substituted.
Design APIs to accept flexible input formats and schema structures, ensuring a better developer experience while maintaining consistency in internal implementation.
For input parameters, support multiple formats where reasonable:
// Instead of requiring only URL objects:
const { text } = await transcribe({
model: revai.transcription('machine'),
audio: new URL('https://example.com/audio.mp3'),
});
// Also support string URLs:
const { text } = await transcribe({
model: revai.transcription('machine'),
audio: 'https://example.com/audio.mp3',
});
For schema definitions, ensure support for flexible structures including additional properties where appropriate:
// Support additional properties in schemas
// e.g., using z.record(z.string()) or additionalProperties in JSON Schema
When implementing format flexibility:
Use straightforward null-safe patterns instead of complex undefined/empty distinctions. Avoid any types that can hide potential null/undefined issues at runtime.
When handling optional values, prefer simple fallback patterns like || {} over complex checks that distinguish between undefined and empty objects. As noted in code reviews, “it’s tricky to depend on a distinction between undefined and empty” because developers often add || {} everywhere, making the distinction unreliable.
Example of preferred approach:
// Prefer this simple pattern
await updateGlobalState("customSupportPrompts", message.values || {})
// Over complex undefined/empty distinctions
if (Object.keys(message?.values ?? {}).length === 0) {
// complex logic here
}
Also avoid any types that mask null safety:
// Avoid
const deleteMessagesForResend = async (cline: any, originalMessageIndex: number) => {
// Prefer explicit typing
const deleteMessagesForResend = async (cline: ClineProvider, originalMessageIndex: number) => {
When working with icon elements in CSS, maintain the specialized font families designed for icon rendering. Replacing icon fonts (like ‘element-icons’) with standard text fonts (like ‘Inter’) will break icon displays that depend on specific glyph mappings in the icon font.
Example of correct usage:
[class^='el-icon-'],
[class*=' el-icon-'] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'element-icons' !important;
}
.selector::after {
position: absolute;
right: 20px;
font-family: 'element-icons';
content: '\e6da'; /* This glyph exists in the icon font */
}
Before changing font-family properties, understand their purpose in the styling system, especially when they relate to icon rendering or special visual elements.
Always sanitize and validate user-controlled input before using it in sensitive operations, and never hard-code credentials in source code.
For command execution:
For credential management:
Bad example (command injection vulnerability):
username = request.get_json().get('username')
os.system(f'docker compose -f {compose_file} -p n8n-{username} up -d')
Better example:
import shlex
import subprocess
username = request.get_json().get('username')
# Validate username format with a strict pattern
if not re.match(r'^[a-zA-Z0-9_-]+$', username):
return jsonify({'error': 'Invalid username format'}), 400
# Use subprocess with parameters list instead of shell=True
subprocess.run(['docker', 'compose', '-f', compose_file, '-p', f'n8n-{username}', 'up', '-d'])
Bad example (credential management):
uri = "mongodb+srv://akaneai420:ilovehentai321@cluster0.jwyab3g.mongodb.net/?retryWrites=true"
Better example:
# Load from environment variables
db_user = os.getenv('DB_USER')
db_password = os.getenv('DB_PASSWORD')
db_host = os.getenv('DB_HOST')
uri = f"mongodb+srv://{db_user}:{db_password}@{db_host}/?retryWrites=true"
These practices help prevent both command injection attacks and credential leakage, which are common security vulnerabilities in web applications.
Never hardcode sensitive information like passwords, API keys, or access tokens directly in code or configuration files (including Dockerfiles). These credentials can be exposed through version control systems, shared images, or when files are accessed by unauthorized users.
Instead:
Example - Insecure:
# Dockerfile.prod
FROM nginx:latest
ENV ADMIN_PASSWORD=supersecret123
Example - Secure:
# Dockerfile.prod
FROM nginx:latest
ENV ADMIN_PASSWORD=${ADMIN_PASSWORD}
# Password will be passed at build/runtime, not stored in file
Choose variable, method, class, and parameter names that clearly communicate their purpose and avoid ambiguity. Names should be self-documenting and specific rather than generic or vague.
Key principles:
max_parse_retries instead of adapter_retry_count, or should_document_method instead of is_documented_methodInputField or enumerate_fields with descriptive ones like UserProfile or get_field_description_stringinput_opt_right and input_opt_left, use clear names like input1 and input2 with explanatory commentstrain_method in one function, use it consistently rather than switching to method elsewhereExample:
# Poor naming - vague and confusing
def enumerate_fields(fields: dict) -> str:
adapter_retry_count = 0
input_opt_right = "test"
# Better naming - descriptive and clear
def get_field_description_string(fields: dict) -> str:
max_parse_retries = 0
user_input = "test"
This approach makes code more maintainable and reduces the cognitive load for other developers reading your code.
When defining exclusion patterns, file filters, or other configuration rules, use specific, targeted patterns rather than broad glob patterns. Overly broad patterns can lead to unintended exclusions and hard-to-debug issues in the future when legitimate files need to be included.
For example, instead of using a broad pattern like !dist/**/*.tgz that excludes all .tgz files from any subdirectory, use a specific pattern like !dist/google-gemini-cli-core-*.tgz that targets only the intended files. This approach:
{
"files": [
"dist",
"!dist/google-gemini-cli-core-*.tgz" // Specific pattern
]
}
This principle applies to all configuration contexts including package.json files arrays, .gitignore patterns, build tool configurations, and other rule-based settings.
Write test assertions that are resilient to implementation changes by focusing on behavior rather than implementation details. Avoid exact matches when partial or behavioral assertions would suffice.
Key practices:
Example - Instead of brittle exact matching:
// ❌ Brittle - breaks if new options are added
expect(options).toEqual({
preview: false,
viewColumn: vscode.ViewColumn.Active
})
// ✅ Resilient - verifies required properties
expect(options).toEqual(expect.objectContaining({
preview: false,
viewColumn: vscode.ViewColumn.Active
}))
For token counting or similar approximate values:
// ❌ Brittle - breaks if tokenizer changes slightly
expect(tokenCount).toBe(14)
// ✅ Resilient - verifies reasonable range
expect(tokenCount).toBeGreaterThan(12)
expect(tokenCount).toBeLessThan(16)
This approach:
Choose descriptive, domain-specific names that clearly communicate intent and prevent confusion. Avoid generic names when more specific alternatives exist, especially when working alongside similar types or concepts from external libraries.
Key principles:
StagehandPage instead of Page to distinguish from Playwright’s Page)systemPrompt instead of instructions)StagehandContainer for HTMLElement | Window)Schema to distinguish type definitions from runtime valuesExample:
// Avoid generic names that could cause confusion
export interface Page extends PlaywrightPage { ... }
// Use descriptive, domain-specific names
export interface StagehandPage extends PlaywrightPage { ... }
// Avoid ambiguous parameter names
function configure(instructions?: string) { ... }
// Use semantically clear names
function configure(systemPrompt?: string) { ... }
This approach makes code self-documenting and reduces cognitive load when working with multiple similar concepts or external dependencies.
Always use proper null safety patterns when accessing properties that might be null or undefined. This prevents runtime errors and improves code robustness.
Key practices:
// ✅ Consistent optional chaining configResult.config?.selectedModelByRole?.chat?.completionOptions
2. Verify object type before accessing properties, especially with DOM elements:
```typescript
// ❌ Unsafe - activeElement could be null
document.activeElement.classList.contains("ProseMirror")
// ✅ Type-safe access
if (document.activeElement instanceof Element &&
document.activeElement.classList.contains("ProseMirror"))
// ✅ Safe with fallback startIndex = nodeTextValue?.indexOf(query, startIndex) ?? -1;
4. Prefer positive conditions for null checks:
```typescript
// ❌ Less readable
onTitleClick={!item.content ? undefined : handleTitleClick}
// ✅ More readable
onTitleClick={item.content ? handleTitleClick : undefined}
When modifying configuration files, ensure all references to the changed values are updated consistently across the entire project. Configuration changes rarely exist in isolation - they often have ripple effects throughout the codebase.
Key guidelines:
Example:
# If changing a package name in package.json:
- "name": "n8n-monorepo",
+ "name": "n8n-official",
# Ensure all references are updated in dependent scripts:
- pnpm --filter n8n-monorepo
+ pnpm --filter n8n-official
Or when modifying workspace paths:
# In devcontainer.json:
- "workspaceFolder": "/workspaces",
+ "workspaceFolder": "/workspaces/n8n",
# Ensure postCreateCommand and other scripts
# are adjusted to work with the new path context
Similarly, when changing TypeScript references or path aliases, audit all dependent configurations to prevent build failures and ensure tooling compatibility.
When configuring LLM providers and their capabilities, always use proper JSON syntax with quoted property names and explicitly declare all relevant capabilities. This ensures your AI models work as expected with the correct features enabled.
For third-party LLM providers:
Example of proper LLM configuration:
{
"models": [
{
"title": "Custom Provider",
"provider": "openai",
"model": "third-party-model",
"contextLength": 8192,
"apiBase": "https://your-api-provider/v1",
"capability": {
"uploadImage": true,
"tools": true
}
}
]
}
Proper configuration prevents runtime errors when using AI features and ensures that all capabilities (like image uploads or tool use) are correctly recognized by the system.
Always sanitize or escape untrusted input before using it in security-sensitive contexts to prevent injection attacks. This includes HTML content that could lead to XSS vulnerabilities and user-provided strings used in regex patterns.
For HTML content, avoid directly rendering untrusted data. Instead of passing raw HTML to iframe srcdoc or similar contexts, use a component library with controlled inputs or implement proper HTML escaping.
For regex patterns, escape special characters in user input before using it in regex construction:
// Vulnerable - user input could inject regex patterns
const regex = new RegExp(`{{${userKey}}}`);
// Safe - escape special characters to treat input as literal text
const regex = new RegExp(`{{\s*${userKey.replace(/[.*+?^${}()|[\]\\]/g, '\$&')}\s*}}`, 'g');
Consider the security implications of any user-controlled data and apply appropriate sanitization based on the context where it will be used.
Always extract configuration values from appropriate sources (config files, environment variables, etc.) rather than hardcoding them in your code. Include validation to ensure the configuration is valid before use, and provide sensible defaults with the ability to override when needed.
Bad practice:
// Hardcoded values that are difficult to maintain
execSync(`code --uninstall-extension rooveterinaryinc.roo-cline`, { stdio: "inherit" })
Good practice:
// Dynamic configuration from package.json
const packageJson = JSON.parse(fs.readFileSync("./src/package.json", "utf-8"))
const publisher = packageJson.publisher
const name = packageJson.name
const extensionId = `${publisher}.${name}`
// Validation before use
const vsixFileName = `./bin/${name}-${version}.vsix`
if (!fs.existsSync(vsixFileName)) {
console.error(`VSIX file not found: ${vsixFileName}`)
process.exit(1)
}
// Allow for overriding defaults
const editorCommand = process.env.EDITOR_COMMAND || "code"
execSync(`${editorCommand} --uninstall-extension ${extensionId}`, { stdio: "inherit" })
This approach improves maintainability, prevents errors when configurations change, and allows your code to work in different environments without modification.
Security features must be tested using the actual executable or CLI rather than just module-level unit tests. This ensures the complete security mechanism works end-to-end in the real execution environment, not just individual components in isolation.
When implementing security controls like environment variable isolation, input validation, or authentication flows, create integration tests that invoke the actual product executable to validate the security behavior works as intended from the user’s perspective.
Example:
// Good: Test security feature with actual CLI
const output = execSync(
`node packages/cli/index.js --ignore-local-env`,
{ cwd: testProjectDir, encoding: 'utf8' }
);
// Verify malicious .env files are NOT loaded
// Avoid: Only testing the security logic in isolation
const result = envLoader.loadWithIsolation(options);
This approach catches security vulnerabilities that might only manifest when all components work together, such as configuration precedence issues, CLI argument parsing bugs, or execution context problems that could bypass security controls.
Every Vue component (.vue file) that is created or modified must have at least one corresponding unit test file. The test must import the component, mount it, and include assertions that validate its behavior.
When modifying an existing component, check for an existing test file (e.g., ComponentName.spec.ts or ComponentName.test.ts) in the same directory or in a dedicated tests directory. If a test exists, update it to cover your changes. If no test exists, create one.
Example test structure:
import { mount } from '@vue/test-utils';
import ComponentName from './ComponentName.vue';
describe('ComponentName', () => {
it('renders correctly', () => {
const wrapper = mount(ComponentName, {
props: {
// required props
}
});
// Assert component renders correctly
expect(wrapper.exists()).toBe(true);
// Assert on specific behavior
expect(wrapper.find('.some-class').exists()).toBe(true);
});
// Additional tests for component behavior
});
This requirement ensures that all Vue components are tested, making the codebase more maintainable and reducing the risk of regressions when components are modified. Tests should verify both rendering and functional aspects of components, particularly focusing on any new or modified features.
Use established naming patterns and correct capitalization throughout the codebase and documentation.
For test fixtures and recordings, follow common conventions like __snapshots__ instead of custom directory names:
// Preferred
// store test recordings in __snapshots__ directory
const testData = require('./__snapshots__/test-response.json');
// Avoid
// using custom or inconsistent directory names
const testData = require('./__data__/test-response.json');
For product and technology names, use proper capitalization and complete names:
// Correct
# Oracle AI Vector Search with LangChain.js Integration
// Incorrect
# Oracle Vector Search with LangchainJS Integration
Consistent naming improves readability, maintainability, and shows professionalism in your code and documentation.
Always use CSS custom properties (CSS variables) for colors and include proper accessibility attributes instead of hard-coded values. This ensures consistency with the design system and improves accessibility for users with visual impairments or different theme preferences.
Color Usage: Replace hard-coded color values with theme-based CSS variables:
// ❌ Avoid hard-coded colors
style={{
backgroundColor: "rgba(255, 191, 0, 0.1)",
border: "1px solid rgba(255, 191, 0, 0.3)",
color: "#FFA500"
}}
// ✅ Use theme-based colors
style={{
backgroundColor: "var(--vscode-inputValidation-warningBackground)",
border: "1px solid var(--vscode-inputValidation-warningBorder)",
color: "var(--vscode-inputValidation-warningForeground)"
}}
Accessibility Attributes: Include appropriate ARIA labels and roles for interactive elements:
// ❌ Missing accessibility attributes
<VSCodeButton onClick={handleCopyCode} title="Copy Code">
// ✅ Include aria-label for screen readers
<VSCodeButton onClick={handleCopyCode} title="Copy Code" aria-label="Copy Code">
// ❌ Clickable div without accessibility
<div onClick={() => { /* handler */ }}>
// ✅ Proper accessibility for interactive elements
<div onClick={() => { /* handler */ }} aria-label="View HTML Content" role="button" tabIndex={0}>
This approach helps users with visual impairments, supports different VS Code themes, and maintains consistency across the application interface.
Technical documentation should always include concrete, working examples that demonstrate the described concepts in action. Examples clarify abstract ideas, illustrate correct usage patterns, and provide templates users can adapt to their needs.
When writing documentation:
For example, when documenting a prompt template feature:
# Example prompt template configuration
promptTemplates:
autocomplete:
template: |
Complete the following code in {{language}}:
File: {{{filename}}}
{{{prefix}}}
# Continue the code here, completing the current statement or function
Examples make documentation more effective by transforming abstract concepts into concrete implementations that users can understand and adapt to their specific needs.
Ensure all configuration options and setup instructions are clearly documented with their intended purposes, use cases, and the most accessible implementation paths. When introducing new configuration classes or setup steps, include contextual descriptions that help users understand when and why to use each option.
For configuration classes, provide clear descriptions of their functionality:
Currently, there are three main agent classes:
* `DefaultAgentConfig`: This is the default agent.
* `RetryAgentConfig`: A "meta agent" that instantiates multiple agents for multiple attempts and then picks the best solution.
* `ShellAgentConfig`: An agent that provides shell-based interaction capabilities for experimental mode and quick interactive workflows.
For setup instructions, prioritize user-friendly approaches and link to simpler alternatives when available:
3. [Install Miniconda](https://docs.anaconda.com/free/miniconda/#quick-command-line-install), then create the `swe-agent` environment with `conda env create -f environment.yml`
This approach helps developers quickly understand available configuration options and reduces setup friction, leading to better adoption and fewer configuration-related issues.
When implementing AI model integrations, maintain consistent interfaces and proper type definitions across different providers. This ensures compatibility, prevents runtime errors, and simplifies maintenance.
Key guidelines:
Example of proper implementation:
// Define shared interface
interface ModelProvider {
embed(chunks: string[], task: EmbeddingTasks): Promise<number[][]>;
chat(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<string>;
}
// Implement provider-specific class
class DeepSeekProvider implements ModelProvider {
// Extend base types for provider-specific features
interface DeepSeekMessage extends ChatMessage {
reasoning_content?: string;
}
// Implement shared interface with provider-specific logic
async embed(chunks: string[], task: EmbeddingTasks): Promise<number[][]> {
// Provider-specific implementation
}
}
This approach:
Replace verbose, complex code structures with simpler, more readable alternatives. Prefer existing methods over inline complex logic, use built-in functions instead of manual implementations, and leverage modern Python features for cleaner code.
Examples of improvements:
if browser_session.is_file_input(element_node): instead of multi-line type checkingscript_content.replace('python', '').replace('', '') instead of complex split logic with potential IndexErrorif (last_action := self.step_results[-1]['actions'][-1])['is_done']This approach reduces code complexity, improves maintainability, and makes the codebase more readable while preventing potential errors from overly complex implementations.
Be intentional when marking functions as async, as it changes the function’s contract and caller expectations. Avoid using async unnecessarily when you’re just returning a promise explicitly, and consider whether making a function async implies that callers should await its completion.
For example, avoid this pattern where async adds no value:
// Unnecessary async - just returning a promise
private static async requestLLMFix(code: string, error: string): Promise<string | null> {
return somePromiseReturningFunction(code, error)
}
Also consider the broader implications when converting functions to async:
// Before: synchronous activation
export function activate(context: vscode.ExtensionContext) {
// setup code
Promise.resolve(vscode.commands.executeCommand("command"))
}
// After: now returns Promise, implying callers should await
export async function activate(context: vscode.ExtensionContext) {
// setup code
await vscode.commands.executeCommand("command")
}
The async version changes the contract - callers now expect to await the activation, which may not be the intended behavior for lifecycle functions.
When writing code, favor simpler, more straightforward implementations over complex ones. Look for opportunities to consolidate logic paths, reduce unnecessary branching, and reuse existing resources instead of recreating them.
This approach improves code readability, reduces maintenance burden, and often leads to better performance. Before implementing complex conditional logic or loading operations, consider if there’s a simpler way to achieve the same result.
Examples of simplification:
self.tools) rather than reloading or recreating themThe goal is to write code that is easier to understand, test, and maintain while achieving the same functionality.
| When providing default values for numeric properties, use the nullish coalescing operator (??) instead of logical OR ( | ). This ensures that valid zero values are preserved rather than being replaced with defaults. Using | will treat 0 as a falsy value and replace it with the default, which is often unintended behavior for numeric settings. |
This pattern is especially important for numeric configurations like thresholds, ranges, and input values where zero is a valid and meaningful value that should not be overridden.
Choose names that precisely reflect the component’s purpose and behavior, avoiding ambiguous terms or shortcuts. Names should be self-documenting and consistent with related components.
Key guidelines:
Example:
# Incorrect - ambiguous or imprecise names
class JSONGenerator:
def generate(self, data: dict) -> dict:
pass
meta_collection = db.get_collection("meta")
def noop_loader(doc: dict) -> dict:
return doc
# Correct - precise, semantic names
class SchematicGenerator:
def generate(self, data: dict) -> dict:
pass
metadata_collection = db.get_collection("metadata")
def identity_loader(doc: dict) -> dict:
return doc
Choose names that clearly communicate the purpose, behavior, or domain concept rather than generic or abbreviated terms. Names should be self-documenting and reflect what the entity actually does or represents.
Replace generic names with descriptive alternatives that convey meaning:
check → coherence_check (specifies what type of check)index → connection_proposition (describes the actual concept)evaluation_service → BehavioralChangeEvaluator (clarifies the specific type of evaluation)Maintain consistency in naming patterns across similar contexts. For example, if addressing an agent in test scenarios, consistently use second person (“when you do X”) rather than mixing with third person (“when the agent does X”).
This approach makes code more readable, reduces the need for additional documentation, and helps maintain consistency across the codebase by establishing clear semantic patterns.
Choose names that clearly communicate purpose and scope rather than generic or overly broad terms. Names should be specific enough to accommodate future variants and descriptive enough to indicate their function without requiring additional context.
Avoid generic package names like “util” in favor of descriptive ones that indicate the specific functionality. When naming themes, configurations, or variants, include distinguishing characteristics to prevent conflicts with future additions.
Examples:
RegisterTheme("catppuccin", ...) use RegisterTheme("catppuccin-mocha", ...) to accommodate other Catppuccin variantsutil.NewFocusTracker() use focus.NewTracker() where the package name describes its purposeThis approach improves code maintainability, reduces naming conflicts, and makes the codebase more self-documenting.
Always document configuration requirements, environment variables, and version specifications to ensure consistent development environments and proper system setup. This includes documenting environment variables that enhance workflow, specifying exact versions in configuration files, and providing clear setup instructions.
For environment variables, document their purpose and usage:
# Terminal sessions now automatically include a $WORKSPACE_ROOT environment variable
# that points to your current workspace root directory
cd $WORKSPACE_ROOT
For development dependencies, reference version specification files and provide setup guidance:
## Prerequisites
1. **Node.js** (LTS version recommended) - see `.nvmrc` for exact version
2. **nvm** - recommended for Node.js version management
This ensures developers can reliably reproduce environments and understand how configuration affects system behavior.
Ensure all references in documentation (file paths, commands, code examples) actually exist in the codebase and accurately reflect the current system state. Additionally, verify that translations maintain correct meaning and grammar in all supported languages.
Examples:
# Incorrect - referencing non-existent script
node test-claude-code-integration.js
# Correct - reference actual test command
npm test -- claude-code.spec.ts
For translated content:
# Incorrect Hindi phrase
हमारी इस डेटा तक पहुंच नहीं है
# Correct Hindi phrase
हमें इस डेटा तक पहुंच नहीं है
Before submitting documentation changes, verify all referenced components exist and translations are grammatically correct and contextually accurate. This ensures documentation remains trustworthy and avoids confusion for developers using it as a reference.
Always use JSDoc format (/** */) instead of regular comments (//) for documenting classes, functions, and interfaces. Documentation should be comprehensive, including:
@internal for non-public API elements{@link ...} syntaxThis ensures that documentation integrates correctly with API reference generators and provides developers with sufficient context.
Example - Before:
// this class uses your clientId, clientSecret and redirectUri
// to get access token and refresh token, if you already have them,
// you can use AuthFlowToken or AuthFlowRefresh instead
export class AuthFlow {
// ...
}
Example - After:
/**
* Authentication flow for obtaining access and refresh tokens using clientId,
* clientSecret and redirectUri.
*
* @example
* const auth = new AuthFlow({
* clientId: process.env.CLIENT_ID,
* clientSecret: process.env.CLIENT_SECRET,
* redirectUri: "http://localhost:3000/callback"
* });
* const tokens = await auth.getTokens();
*
* @see If you already have tokens, consider using {@link AuthFlowToken} or
* {@link AuthFlowRefresh} instead.
*/
export class AuthFlow {
// ...
}
Avoid using generic suffixes like “Response”, “Result”, or “Request” in type names, especially for non-request types. Instead, use semantic names that describe the actual data structure and can be reused throughout the codebase.
Generic suffixes make types less reusable and create unnecessary coupling to specific API contexts. Semantic names promote code reuse and better express the domain concepts.
Example:
// Avoid
message AvailableTerminalProfilesResponse {
repeated string profiles = 1;
}
message StringArrayResponse {
repeated string values = 1;
}
// Prefer
message TerminalProfiles {
repeated string profiles = 1;
}
message StringArray {
repeated string values = 1;
}
This approach makes types more generic and reusable across different parts of the codebase, not just in API handlers.
When adding new models to configuration files, ensure all required configuration fields are populated, not just the model name in the running_models list. Models need complete configuration in both JSON (known_models.json) and YAML (provider files) with all necessary fields specified.
Required fields typically include:
n_ctx: Context window sizesupports_tools: Tool calling capabilitysupports_multimodality: Image/file supportsupports_agent: Agent functionalitytokenizer: Tokenizer pathExample of complete configuration:
# In provider YAML file
running_models:
- claude-4
chat_models:
claude-4:
n_ctx: 200000
supports_tools: true
supports_multimodality: true
supports_clicks: true
supports_agent: true
supports_reasoning: anthropic
tokenizer: hf://Xenova/claude-tokenizer
Incomplete configurations where only the model name is added to running_models without corresponding detailed configuration will result in runtime errors or unexpected behavior. Always cross-reference known_models.json to understand which configuration fields are required for proper model functionality.
Before using secrets in CI/CD workflows that can be triggered by external contributors (forks, dependabot), assess the “blast radius” of potential secret compromise. Differentiate between high-risk secrets that provide infrastructure access and limited-scope secrets with constrained permissions.
High-risk secrets (avoid in external-triggerable workflows):
Limited-scope secrets (may be acceptable with proper controls):
Example from workflow configuration:
# Acceptable: Chromatic token only allows snapshot uploads
- name: Run Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
Always implement additional safeguards like requiring approval for external PR workflows, and document the security tradeoffs when using any secrets in publicly-triggerable workflows.
Define a clear, hierarchical structure for application configurations with descriptive naming and proper organization. Avoid hardcoded values, use named constants for magic numbers, and ensure configuration is loaded only once at startup and passed through the application rather than loaded at arbitrary points.
Key practices:
// Avoid
const deadline = Date.now() + 1000;
// Better
const PROCESS_TERMINATION_TIMEOUT_MS = 1000;
const deadline = Date.now() + PROCESS_TERMINATION_TIMEOUT_MS;
// Avoid
output: {
maxBytes: 12410,
maxLines: 256
}
// Better
tools: {
shell: {
maxBytes: 12410,
maxLines: 256
}
}
// Avoid
client_id: "Iv1.b507a08c87ecfe98"
// Better
client_id: process.env.GITHUB_CLIENT_ID || config.github.clientId
// Avoid
function someFunction() {
const config = loadConfig(); // Loading config at arbitrary points
// ...
}
// Better
function someFunction(config) { // Config passed as parameter
// ...
}
// Avoid
const providersConfig = config.providers; // Could be undefined
// Better
const providersConfig = config.providers ?? defaultProviders;
Following these practices makes configurations more maintainable, testable, and prevents unpredictable behavior in long-running applications when configurations change during execution.
Avoid duplicating logic across the codebase. Instead, extract common functionality into well-named helper functions or standalone utilities. This improves code readability, simplifies maintenance, and centralizes logic for easier updates.
Examples where this applies:
Before:
if (provider.toLowerCase() === "githubcopilot" && !apiKey) {
apiKey = await fetchGithubCopilotApiKey();
// Additional logic for handling the API key...
} else if (cli.flags.login) {
if (provider.toLowerCase() === "githubcopilot") {
apiKey = await fetchGithubCopilotApiKey();
// Duplicate logic...
}
}
After:
function handleGithubCopilotLogin() {
// Centralized login logic
}
if (provider.toLowerCase() === "githubcopilot" && !apiKey) {
apiKey = await handleGithubCopilotLogin();
} else if (cli.flags.login) {
if (provider.toLowerCase() === "githubcopilot") {
apiKey = await handleGithubCopilotLogin();
}
}
Design AI integration code to be provider-agnostic, avoiding assumptions that all models will come from a single provider. Implement explicit handling for known models while maintaining fallback mechanisms for others.
For example, when determining model capabilities like context length:
function maxTokensForModel(model: string): number {
// First check if it's a known model in our registry
if (openAiModelInfo[model]) {
return openAiModelInfo[model].maxContextLength;
}
// Fallback to pattern-based detection for other providers
const lower = model.toLowerCase();
if (lower.includes("32k")) {
return 32000;
}
if (lower.includes("16k")) {
return 16000;
}
if (lower.includes("8k")) {
return 8000;
}
if (lower.includes("4k")) {
return 4000;
}
return 128000; // Default fallback
}
Similarly, when instantiating clients, reuse existing ones when possible rather than creating provider-specific instances that duplicate logic and may drift in configuration.
Tests should not rely on external URLs, live websites, or internet connectivity to ensure reliability, consistency, and faster execution. External dependencies can cause tests to fail due to network issues, website changes, or unavailability, making CI/CD pipelines unstable.
Instead of using live URLs, use these alternatives:
chrome://version, about:blank, or similar built-in pagesExample of problematic code:
await page.goto('https://example.com') # External dependency
await page.goto('https://browserleaks.com/javascript') # External dependency
Example of improved code:
# Use pytest-httpserver (see test_controller.py)
await page.goto(f'http://localhost:{server.port}/test-page')
# Or use local browser pages
await page.goto('about:blank')
await page.goto('chrome://version')
This approach eliminates external dependencies, makes tests more reliable, reduces execution time, and ensures consistent results across different environments and network conditions.
When modifying existing APIs, ensure backward compatibility to prevent runtime failures and minimize migration effort for consumers. Breaking changes in function signatures, return types, or parameter requirements can cause cascading issues throughout a codebase.
Follow these practices for API evolution:
// Bad: Breaking change - adding a required parameter
- embed(chunks: string[]): Promise<number[][]>;
+ embed(chunks: string[], embedding_task: EmbeddingTasks): Promise<number[][]>;
// Good: Backward compatible change
+ embed(chunks: string[], embedding_task?: EmbeddingTasks): Promise<number[][]>;
// Bad: Breaking return type change
- function compileChatMessages(...): ChatMessage[] {
+ function compileChatMessages(...): { compiledChatMessages: ChatMessage[]; lastMessageTruncated: boolean } {
// Good: Backward compatible approach
+ interface ChatMessagesResult {
+ messages: ChatMessage[];
+ lastMessageTruncated?: boolean;
+ }
+ function compileChatMessages(...): ChatMessagesResult {
// Bad: Making previously optional parameters required
- required: ["name", "rule"],
+ required: ["name", "rule", "alwaysApply", "description"],
// Good: Keep core parameters required, make new ones optional
+ required: ["name", "rule"],
+ properties: {
+ alwaysApply: { type: "boolean", default: false },
+ description: { type: "string", default: "" },
+ }
Remember that every API change affects all dependent code. Taking the time to design evolution-friendly interfaces upfront prevents costly migrations later.
Configuration schemas should explicitly define all required fields and validate types at compile time to prevent runtime errors. Use strict typing with clear validation rules, and avoid marking required fields as optional.
Example:
// ❌ Problematic: Required field marked as optional
const configSchema = z.object({
modelArn: z.string().optional(), // Could cause runtime errors
});
// ✅ Better: Explicit required/optional fields
const configSchema = z.object({
modelArn: z.string(), // Required field
profile: z.string().optional(), // Truly optional field
region: z.string().optional(),
});
// Add runtime validation
function validateConfig(config: Config) {
const result = configSchema.safeParse(config);
if (!result.success) {
throw new ValidationError(result.error.errors);
}
}
This approach:
Ensure that promises are either resolved or rejected, but never both. When handling promise resolution in callbacks or event handlers, use proper conditional logic to guarantee mutual exclusion between success and error paths.
For example, this pattern creates inconsistent promise states:
return new Promise((resolve, reject) => {
child.on("message", (msg) => {
if (msg.error) {
reject();
}
resolve(); // Problem: This always executes regardless of error state
});
});
Instead, use an else block to ensure mutual exclusion:
return new Promise((resolve, reject) => {
child.on("message", (msg) => {
if (msg.error) {
reject();
} else {
resolve(); // Correct: Only resolves if there is no error
}
});
});
This prevents inconsistent promise states where both error and success handlers might execute, leading to unpredictable application behavior and hard-to-debug issues.
When implementing functionality to bypass security controls (like sandboxing), ensure the bypass is complete and explicit rather than just configuring existing security mechanisms to be permissive. Create dedicated code paths for unrestricted operation that truly bypass all security layers.
For example, instead of:
pub fn new_unrestricted_policy() -> Self {
// This still uses the sandbox with relaxed permissions
SandboxPolicy {
allow_disk_read: true,
allow_disk_write: true,
allow_network: true,
auto_approve: true,
}
}
Implement a truly separate path:
pub fn new_unrestricted_policy() -> Self {
// Explicitly use NoSandbox implementation
SandboxPolicy {
sandbox_type: SandboxType::NoSandbox,
// other fields as needed
}
}
This prevents subtle security issues where sandboxing mechanisms might still be partially active despite intending to fully bypass them.
When reading configuration from multiple sources (function arguments, environment variables, config files, defaults), implement and preserve a single, explicit precedence order, and ensure user-provided overrides beat environment-derived values.
Apply this consistently:
Example pattern (proxy mounts precedence):
# env_proxies: dict[str, str|None]
proxy_map = {k: None if v is None else Proxy(url=v) for k, v in get_environment_proxies().items()}
proxy_mounts = {
k: None if p is None else AsyncHTTPTransport(proxy=p, **transport_kwargs)
for k, p in proxy_map.items()
}
# User mounts override env-derived mounts
mounts = dict(proxy_mounts)
mounts.update(kwargs.get("mounts", {}))
kwargs["mounts"] = mounts
Use Python’s expressive features to write cleaner, more maintainable code by reducing nesting and improving readability. Follow these practices:
if not FOUNDRY_AVAILABLE: raise ImportError(“Foundry Agent Dependencies are not installed.”) else: # Do something
if not FOUNDRY_AVAILABLE: raise ImportError(“Foundry Agent Dependencies are not installed.”)
2. **Use walrus operators** for concise assignment in conditional expressions:
```python
# Instead of this:
knowledge_storage = getattr(agent, "knowledge", None)
if knowledge_storage is not None:
knowledge_storage.reset()
# Do this:
if (knowledge_storage := getattr(agent, "knowledge", None)) is not None:
knowledge_storage.reset()
try: for frame_info in stack: candidate = frame_info.frame.f_locals.get(“self”) if isinstance(candidate, Flow): self.parent_flow = candidate break else: self.parent_flow = None finally: del stack
try:
self.parent_flow = None
for frame_info in stack:
candidate = frame_info.frame.f_locals.get(“self”)
if isinstance(candidate, Flow):
self.parent_flow = candidate
break
return self
finally:
del stack
4. **Simplify conditional logic** with default assignments:
```python
# Instead of this:
if not memory_path:
memory_path = db_storage_path()
# Do this:
memory_path = memory_path or db_storage_path()
These practices help reduce cognitive load when reading code and make it easier to spot logical errors. They also lead to more maintainable code by limiting nesting depth and reducing unnecessary verbosity.
Prefer environment variables over hardcoded configuration values to improve flexibility and avoid forcing configuration choices on users. Always provide sensible defaults and implement proper validation.
Use environment variables for:
Implementation pattern:
# Good: Environment variable with default and validation
search_engine = os.getenv('BROWSERUSE_SEARCH_ENGINE', 'google').lower().strip()
assert search_engine in ['google', 'bing', 'duckduckgo']
# Good: Configurable port instead of hardcoded
port = int(os.getenv('CHROME_REMOTE_DEBUGGING_PORT', '9222'))
endpoint_url = f'http://localhost:{port}'
# Good: Utility function for env var validation
def check_env_variables(keys: list[str], any_or_all=all) -> bool:
return any_or_all(os.getenv(key, '').strip() for key in keys)
# Bad: Hardcoded configuration
CAMOUFOX = True # Should be os.getenv('USE_CAMOUFOX', 'false').lower() == 'true'
This approach allows users to customize behavior without code changes while maintaining reasonable defaults for common use cases. Create reusable utility functions for environment variable validation that can be imported across the codebase.
When building applications that interact with AI models, avoid hardcoding model-specific behavior and instead design for flexibility across different LLM providers and versions. This approach increases resilience and makes your code more maintainable as the AI ecosystem evolves.
Key practices:
Example:
# Instead of this:
def process_with_ai(prompt, model="gpt-4o"):
client = OpenAI()
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Do this:
def process_with_ai(prompt, llm=None):
llm = llm or get_default_llm()
# Validate LLM instance early
if not hasattr(llm, 'call') or not callable(llm.call):
raise ValueError("Invalid LLM instance: missing call method")
# Use provider-agnostic interface
return llm.call([{"role": "user", "content": prompt}])
def get_default_llm():
# Create default LLM instance with appropriate config
return BaseLLM(model="default-model")
This approach lets you easily switch models, test with mock LLMs, and adapt to new model APIs without changing your core application logic.
Always use the proper logger instance instead of console methods, and format error logs with structured data objects rather than string concatenation. Console logging methods like console.error can lead to log flooding in production and lack proper log level controls. Structured logging with error objects enables better log parsing, monitoring, and debugging.
Avoid:
console.error('Schema validation error: Detected unconverted Zod schema');
logger.error(`Failed to scrape URL ${url}: ${scrapeResponse.error}`);
Use instead:
logger.error('Schema validation error: Detected unconverted Zod schema', {
type: val._def?.typeName,
keys: Object.keys(val),
hasZodProperties: !!(val._def || val.parse || val.safeParse)
});
logger.error(`Failed to scrape URL ${url}`, { error: scrapeResponse.error });
This approach provides consistent logging behavior across environments, enables proper log level filtering, and creates structured data that monitoring tools can easily parse and alert on.
Identifiers (variables, properties, keys, IDs) should accurately reflect their semantic purpose and context. Names should be chosen to clearly communicate the meaning and role of the element within its specific context, not just its technical type or generic purpose.
Examples:
// Incorrect: Name doesn't match context
const hasCustomTemperature = value !== undefined
// Correct: Name reflects actual context
const hasCustomMaxContext = value !== undefined
// Incorrect: Generic/mismatched test ID
data-testid="open-tabs-limit-slider"
// Correct: ID reflects component purpose
data-testid="markdown-lineheight-slider"
// Incorrect: Inconsistent API property naming
interface Props {
apiRequestFailedMessage: string;
apiReqStreamingFailedMessage: string; // Inconsistent abbreviation
}
// Correct: Consistent naming pattern
interface Props {
apiRequestFailedMessage: string;
apiRequestStreamingFailedMessage: string;
}
This standard helps maintain code clarity, improves maintainability, and reduces cognitive load by ensuring names accurately represent their purpose within the codebase.
Always explicitly configure important system components rather than relying on implicit defaults or environment variables. Document required configuration combinations and version requirements clearly to prevent subtle errors.
For example:
postgres_storage = LTMPostgresStorage( connection_string=”postgresql://username:password@hostname:5432/database” ) long_term_memory = LongTermMemory(storage=postgres_storage)
crew = Crew( agents=[…], tasks=[…], memory=True, long_term_memory=long_term_memory, entity_memory=EntityMemory() )
- For version requirements, specify exact minimum versions (e.g., Python >=3.10) rather than recommendations when functionality depends on it
- When adding configuration flags, use consistent, explicit naming that clearly communicates scope and function (like `-kn` for all knowledge and `-akn` for agent-specific knowledge)
---
## Avoid hardcoded API assumptions
<!-- source: browser-use/browser-use | topic: API | language: Python | updated: 2025-06-09 -->
API interfaces should not contain hardcoded implementation details or assume specific underlying technologies. Instead, make them configurable and implementation-agnostic to support different backends and configurations.
When designing APIs, avoid embedding specific service names, browser types, or implementation details directly in the interface. Use dynamic configuration or parameterization instead.
Example of problematic hardcoded approach:
```python
@self.registry.action(
'Search the query in Google, the query should be a search query...',
param_model=SearchGoogleAction,
)
browser = await browser_class.launch(
headless=self.config.headless,
channel='chrome', # Hardcoded despite browser_class potentially being firefox/webkit
)
Better approach with configurable implementation:
@self.registry.action(
f'Search the query in {self.search_engine.title()}, the query should be a search query...',
param_model=SearchAction,
)
# Use appropriate channel based on browser type or make it configurable
browser = await browser_class.launch(
headless=self.config.headless,
channel=self.get_appropriate_channel(browser_class),
)
This ensures APIs remain flexible and can adapt to different implementations without requiring interface changes.
Choose null checking patterns based on your function’s purpose and intended behavior with empty values. For functions with fallback strategies, consider whether empty strings should trigger alternative methods or be treated as valid results.
Use if (value?.property) when empty strings should be treated as falsy and trigger fallback logic:
// Content extraction with fallbacks
if (article?.textContent) {
return postProcessText(article.textContent)
}
// Falls through to try other extraction methods
Use if (value?.property != null) when you need to distinguish null/undefined from empty strings:
// When empty string is a valid result
if (article?.textContent != null) {
return article.textContent // Returns empty string if that's what was parsed
}
Consider the downstream impact: will your function benefit from attempting alternative strategies when the primary method yields empty content, or should empty results be preserved and returned immediately?
When working with AI models and LLMs, optimize both prompts and input data to improve model performance and reduce token usage. For prompts, be specific about the AI’s role, requirements, and expected output format rather than using vague instructions. For input data, preprocess and clean content to remove unnecessary elements that could confuse the model or waste tokens.
Example of improved prompt specificity:
// Instead of vague prompts:
const prompt = `Translate the following into ${language} and only show me the translated content`
// Use specific, role-based prompts:
const prompt = `You are a professional translator. Translate the following text into ${language}, preserving meaning, tone, and formatting. Only provide the translated result.`
Example of input data cleaning:
// Clean subtitle data before sending to AI
subtitleContent = replaceHtmlEntities(subtitleContent.replace(",", " "))
This approach reduces confusion, improves output quality, and optimizes token usage when interacting with AI models.
Names should clearly communicate purpose, relationships, and domain context. Choose identifiers that reveal intent and accurately describe what they represent:
Class/component names should reflect relationships - Name components to show their relationship with other entities. For example, prefer TaskGuardrail over GuardrailTask to indicate it’s a guardrail for tasks, not a task type.
Use domain-specific naming - Avoid generic names when domain-specific terms can provide context. For instance, use crewai_events instead of generic event_bus to clearly indicate the domain.
# Good - name clearly indicates action
def _get_context(self, task, task_outputs):
# Method retrieves context
# Confusing - doesn't clearly indicate if setting or getting
def _context(self, task, task_outputs):
# Purpose unclear from name
# Good - name indicates specific model type support
def __init__(self, openai_model_name: str):
self.model = openai_model_name
# Misleading - suggests any model type works
def __init__(self, model: str):
self.model = model # Actually only works with OpenAI
AgentInterface rather than AgentWrapperParent).Choose appropriate timing intervals for asynchronous operations to improve performance and responsiveness. For frequent polling of cheap operations, use shorter intervals (200ms instead of 1s) to reduce latency. For potentially blocking file system operations, use atomic patterns like rename-then-delete to avoid blocking the async runtime.
Example of optimized polling:
// Instead of 1-second polling
tokio::time::sleep(Duration::from_secs(1)).await;
// Use shorter intervals for cheap status checks
tokio::time::sleep(Duration::from_millis(200)).await;
Example of non-blocking file operations:
// Instead of direct removal that can block
tokio::fs::remove_dir_all(&path).await;
// Use atomic rename then remove pattern
let temp_path = path.with_extension("to-remove");
tokio::fs::rename(&path, &temp_path).await?;
tokio::fs::remove_dir_all(&temp_path).await;
This approach reduces unnecessary waiting time for responsive operations while preventing blocking operations from degrading overall system performance.
Use direct process.env access and standardized configuration management instead of custom environment variable wrappers. Avoid redundant abstraction layers when the framework or libraries already handle environment variable inference automatically.
Key principles:
process.env.VARIABLE_NAME instead of custom env objects when possible@t3-oss/env-nextjs package for environment variable validation and type safetyENABLED_XXX for feature flags and XXX_API_KEY for API keyssrc/config/app.ts)AUTH_XXX variables)Example:
// ❌ Avoid custom wrappers when direct access works
clientId: authEnv.AUTH_GOOGLE_CLIENT_ID ?? process.env.AUTH_GOOGLE_CLIENT_ID
// ✅ Use direct access for new implementations
clientId: process.env.AUTH_GOOGLE_CLIENT_ID
// ✅ Use @t3-oss/env-nextjs for validation
import { createEnv } from '@t3-oss/env-nextjs';
export const appEnv = createEnv({
server: {
ENABLED_CLOUDFLARE: z.boolean().default(false),
CLOUDFLARE_API_KEY: z.string().optional(),
}
});
This approach reduces complexity, improves maintainability, and leverages existing framework capabilities for environment variable management.
Add comprehensive JSDoc comments to all API interfaces, types, and schema definitions. This documentation should:
This practice improves developer experience through enhanced IDE tooltips and makes the code more maintainable by new team members.
Example:
/**
* Web search tool result error content
* @see https://docs.anthropic.com/en/docs/build-with-claude/tool-use/web-search-tool#errors
*/
export interface AnthropicWebSearchToolResultErrorContent {
/** Identifies this as a web search tool error response */
type: 'web_search_tool_result_error';
/** Error code from the API (e.g., 'max_uses_exceeded', 'too_many_requests') */
error_code: string;
}
// For schemas with multiple properties:
const providerOptionsSchema = z.object({
/** Language code (ISO-639-1) for transcription, e.g. 'en-US' */
language: z.string().nullish(),
/** Start position in seconds for partial audio processing */
audioStartAt: z.number().int().nullish(),
});
Maintain clear and explicit code organization patterns by following these guidelines:
Example:
// ❌ Avoid
export * from './utils';
import { something } from './index';
class MyClass {
private messages: Message[];
getMessages() { return this.messages; }
}
// ✅ Better
export { generateId, parseConfig } from './utils';
import { something } from './something';
class MyClass {
#internalState: string;
messages: Message[]; // public property when no special handling needed
}
This pattern improves code maintainability, makes dependencies clear, and helps control your public API surface.
When null or undefined values represent meaningful absence of data, preserve them rather than converting to default values like empty strings, arrays, or placeholder text. Converting these values can lose semantic meaning and create unnecessary data storage or processing overhead.
For example, prefer null over string literals for unknown enum values:
// Avoid - stores unnecessary text in database
export enum IntegrationEnum {
UNKNOWN = "unknown"
}
// Prefer - null represents true absence
export enum IntegrationEnum {
// omit unknown case, handle with null checks
}
Similarly, when making parameters optional, let undefined flow through rather than converting to defaults:
// Avoid - loses the semantic difference between undefined and empty
let jsonData = { urls: urls || [], ...params };
// Prefer - preserves undefined semantics
let jsonData = { urls, ...params };
This approach maintains clearer data contracts and prevents ambiguity between “no data provided” and “empty data provided”.
Minimize nested conditional statements and complex control flow by using early returns, guard clauses, and default value patterns. This improves code readability and maintainability by reducing cognitive load.
Use the or operator for default values instead of conditional checks:
# Instead of:
if modules_to_serialize is not None:
# process modules_to_serialize
else:
modules_to_serialize = []
# Use:
modules_to_serialize = modules_to_serialize or []
Restructure conditional logic to reduce nesting:
# Instead of:
result = dict(usage_entry2)
for k, v in usage_entry1.items():
if isinstance(v, dict):
if k in result:
result[k] = self._merge_usage_entries(result[k], v)
else:
result[k] = dict(v) if isinstance(v, dict) else v
else:
result[k] = result[k] or 0
result[k] += v if v else 0
# Use:
result = dict(usage_entry2)
for k, v in usage_entry1.items():
current_v = result.get(k)
if isinstance(v, dict):
result[k] = self._merge_usage_entries(current_v, v)
else:
result[k] = current_v or 0
result[k] += v if v else 0
For functions with many parameters, use multi-line formatting:
# Instead of:
def __call__(self, lm: LM, lm_kwargs: dict[str, Any], signature: Type[Signature], demos: list[dict[str, Any]], inputs: dict[str, Any]) -> list[dict[str, Any]]:
# Use:
def __call__(
self,
lm: LM,
lm_kwargs: dict[str, Any],
signature: Type[Signature],
demos: list[dict[str, Any]],
inputs: dict[str, Any]
) -> list[dict[str, Any]]:
Always perform explicit null and undefined checks before accessing object properties or using values in operations. Filter out undefined values from arrays and collections to prevent runtime errors and unexpected behavior.
Key practices:
typeof value === "object" && value !== null)"tool_call_id" in msg)Example:
// Good: Explicit null check prevents runtime errors
if (typeof value === "object" && value !== null) {
// Safe to access properties
}
// Good: Check property existence and filter undefined values
const toolMessages = tailMessages
.filter(msg => "tool_call_id" in msg)
.map(msg => msg.tool_call_id)
.filter(id => id !== undefined);
// Good: Validate before property access
if (maybeLastAssistantMessageUsage) {
const allMatch = Object.entries(currentUsage).every(
([key, value]) => maybeLastAssistantMessageUsage[key] === value
);
}
Wrap operations that can fail in try/catch blocks to prevent unhandled exceptions from crashing the application or leaving it in an inconsistent state. This is especially important for file operations, API calls, and critical initialization code.
Operations that commonly need error handling include:
Example of adding error handling to extension activation:
export async function activate(context: vscode.ExtensionContext) {
try {
// Extension initialization code that might fail
await initializeExtension(context)
} catch (error) {
console.error("Failed to activate extension:", error)
// Handle gracefully or show user-friendly error
}
}
Example of adding error handling to file operations:
async function deleteTaskWithId(id: string) {
try {
if (id === this.cline?.taskId) {
await this.clearTask()
}
// File deletion operations that can fail
await fs.unlink(apiConversationHistoryFilePath)
await fs.unlink(uiMessagesFilePath)
} catch (error) {
console.error("Error deleting task files:", error)
// Handle cleanup or notify user
}
}
Without proper error handling, exceptions can be lost, operations can fail silently, or the entire application can crash unexpectedly. Always consider what can go wrong and provide appropriate error handling with meaningful error messages.
Names should clearly and accurately convey their purpose, behavior, and content. Follow these guidelines:
// Good const IS_NEXT_EDIT_ACTIVE = true; if (IS_NEXT_EDIT_ACTIVE) { … }
2. Method names should precisely reflect their behavior:
- Use verbs that accurately describe the action
- Include plurality when handling multiple items
- Avoid ambiguous terms like "set" when "add" or "update" are more accurate
```typescript
// Bad
setDecoration(editor: Editor, ranges: Range[]) // "set" implies replacement
userId(): string // doesn't indicate it's a check
// Good
addDecorations(editor: Editor, ranges: Range[]) // clearly shows augmenting
isSignedIn(): boolean // clearly shows purpose
// Good tokenBudget: number // clearly indicates purpose
This standard helps maintain code clarity, reduces confusion, and makes intentions immediately clear to other developers.
---
## Consistent terminology usage
<!-- source: browser-use/browser-use | topic: Naming Conventions | language: Python | updated: 2025-05-30 -->
Maintain consistent terminology and naming patterns throughout the codebase to avoid confusion and future conflicts. Use descriptive names that clearly indicate their purpose and remove unnecessary parameters or elements that don't serve a function.
Key principles:
- Keep consistent naming across the entire codebase, even if the underlying implementation might change
- Use semantic names that clearly describe the function or purpose (e.g., `on_step_start`/`on_step_end` instead of `before_step_func`/`after_step_func`)
- Remove unused parameters or fields that don't contribute to functionality
- Consider future extensibility when choosing terminology to avoid naming conflicts
Example from the discussions:
```python
# Good: Consistent terminology maintained across codebase
self.playwright = self.playwright or await self.playwright.chromium.connect_over_cdp(...)
# Avoid: Introducing conflicting terminology
self.driver = self.driver or await self.playwright.chromium.connect_over_cdp(...)
# Good: Descriptive parameter names
async def run(
self,
max_steps: int = 100,
on_step_start: AgentHookFunc | None = None,
on_step_end: AgentHookFunc | None = None
):
# Good: Remove unused parameters
class ExtractElementHtmlAction(BaseModel):
index: int
format: Literal['text', 'markdown', 'html'] = 'html'
# xpath removed as it wasn't being used
This approach prevents terminology conflicts, improves code readability, and makes the codebase more maintainable by ensuring names accurately reflect their purpose and usage.
When processing large arrays or data structures, implement chunked processing to avoid stack size limitations and optimize performance. Break operations into manageable chunks rather than processing everything at once.
Key practices:
reduce() when accumulating or combining values across collectionsmap() when transforming elements without combining themExample:
// Process large binary data in chunks to avoid stack overflow
async asString(): Promise<string> {
const data = this.data ?? new Blob([]);
const dataBuffer = await data.arrayBuffer();
const dataArray = new Uint8Array(dataBuffer);
// Need to handle the array in smaller chunks to deal with stack size limits
let ret = "";
const chunkSize = 102400;
for (let i = 0; i < dataArray.length; i += chunkSize) {
const chunk = dataArray.subarray(i, i + chunkSize);
ret += String.fromCharCode(...chunk);
}
return ret;
}
Implementing chunked processing improves application stability by preventing stack overflows and can improve performance by managing memory more efficiently. This pattern is especially important when handling user-generated content, large API responses, or binary data operations.
Always validate network connection states and implement explicit timeout handling to prevent zombie connections and ensure robust network operations. Connection objects can appear valid while actually being disconnected, and network operations without timeouts can hang indefinitely.
When working with browser contexts or network connections, actively verify the connection state rather than assuming validity:
# Validate browser connection state
if self.browser_context:
try:
_ = self.browser_context.pages
if self.browser_context.browser and not self.browser_context.browser.is_connected():
self.browser_context = None
except Exception:
self.browser_context = None
For network operations, always specify explicit timeouts with reasonable defaults:
# Add timeout parameter to network operations
await page.goto(params.url, timeout=int((params.timeout or 30)*1000))
This prevents hanging operations and provides predictable failure modes when network conditions are poor or connections are unstable.
All file-related operations must implement comprehensive input validation and sanitization to prevent path traversal attacks, arbitrary file system access, and execution of malicious content. This is especially critical when handling user-provided file paths or when systems interact with AI agents that could be manipulated through prompt injection.
Key validation requirements:
.txt, .pdf) based on the use case..., /, or \ characters. Validate that paths don’t resolve to dangerous system directories./, ~, ~/Desktop, ~/Documents. Restrict operations to dedicated safe directories or current working directory.#! at file start and verify no executable permission bits are set after file creation.Example implementation:
def validate_file_path(file_path: str, allowed_extensions: list[str]) -> str:
# Check for dangerous directories
dangerous_paths = ['/', '~', '~/Desktop', '~/Documents']
if file_path in dangerous_paths:
raise ValueError(f"Access to {file_path} is not allowed")
# Extract filename and validate
filename = Path(file_path).name
# Sanitize filename
sanitized = re.sub(r'[^a-zA-Z0-9 _-]', '_', filename)
if len(sanitized) > 64:
sanitized = sanitized[:64]
# Check extension
if not any(sanitized.endswith(ext) for ext in allowed_extensions):
raise ValueError(f"File extension not allowed: {sanitized}")
return sanitized
This prevents AI agents or malicious users from writing to system files, executing scripts, or accessing sensitive directories through path traversal attacks.
Be cautious about what data gets included in log messages to prevent security risks and performance issues. Before logging file contents or user data, consider whether it could contain:
Instead of logging full content, log metadata like file names, sizes, types, or character counts. Use appropriate log levels - consolidate related error information into a single error log rather than splitting across multiple log statements.
Example of what to avoid:
# Bad - logs potentially sensitive/large content
file_content = file_system.read_file(file_name)
logger.info(f'Read file contents: {file_content}')
# Bad - splits error information
logger.info("error during llm invocation")
logger.error(e)
Example of better approach:
# Good - logs metadata only
file_content = file_system.read_file(file_name)
logger.info(f'Read file {file_name} ({len(file_content)} characters)')
# Good - consolidated error logging
logger.error(f"Error during LLM invocation: {e}")
Always pin external dependencies to specific commit hashes rather than mutable references like tags or branch names to prevent supply chain attacks. This applies to GitHub Actions, package dependencies, Docker images, and similar resources - even if they’re from your own repositories.
If a dependency repository is compromised, using mutable references makes it easier for attackers to execute lateral movement into your project. While using tags like @latest or @beta is more convenient, it introduces significant security vulnerabilities.
Example:
# Insecure - using mutable tag references
- name: Checkout repository
uses: actions/checkout@v4
# Secure - pinning to specific commit hash
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
Consider implementing automation to update these hashes regularly while maintaining the security benefits of pinning specific versions.
When creating performance optimization tools, especially temporary dev-only utilities, clearly document their purpose, scope, and removal criteria in the README or documentation. This helps teams make informed decisions about maintenance vs. performance benefits over time.
Include these key elements:
Example documentation:
# Translation MCP Server
**Kilocode internal dev tool only:** This is a performance optimization to reduce LLM waiting time during translation tasks. Can be deleted when maintenance burden outweighs time saved.
This approach prevents performance tools from becoming technical debt by establishing upfront expectations about their lifecycle and making it easier for future developers to evaluate whether the optimization is still worthwhile.
Always validate and sanitize user-provided inputs before using them in sensitive contexts like SQL queries, file paths, or URL requests. This prevents SQL injection, path traversal, SSRF, and similar attacks.
For SQL queries, use parameterized queries instead of string concatenation:
// UNSAFE - vulnerable to SQL injection:
const query = `SELECT column_name FROM information_schema.columns WHERE table_name = '${tableName}'`;
// SAFE - using parameterized queries:
const query = `SELECT column_name FROM information_schema.columns WHERE table_name = ?`;
await connection.execute(query, [tableName]);
For file paths, validate against directory traversal attempts:
// Validate that paths don't try to escape the intended directory
if (path.includes('..') || path.startsWith('/') || path.includes('\\')) {
throw new Error("Invalid path: directory traversal attempt detected");
}
For URL requests, implement validation and consider using allowlists:
function isValidUrl(url: string): boolean {
try {
const parsedUrl = new URL(url);
// Check against allowlist of domains or protocols
return ['https:'].includes(parsedUrl.protocol) &&
ALLOWED_DOMAINS.includes(parsedUrl.hostname);
} catch {
return false;
}
}
if (!isValidUrl(userProvidedUrl)) {
throw new Error("Invalid or disallowed URL");
}
When developing API endpoints or libraries, clearly document in JSDoc comments which parameters must come from trusted sources and cannot accept direct user input.
When integrating AI models into applications, provide consistent configuration methods that support different access patterns (direct API, chat interfaces, or intermediary services like LiteLLM).
Key practices:
LITELLM_BASE_URL, OPENAI_API_KEY)Example:
def create_model(model_name, **kwargs):
# Support prefix-based mode selection
COPY_PASTE_PREFIX = "cp:"
copy_paste_mode = model_name.startswith(COPY_PASTE_PREFIX)
if copy_paste_mode:
model_name = model_name.removeprefix(COPY_PASTE_PREFIX)
# Support environment variables for configuration
base_url = os.environ.get("MODEL_API_BASE_URL")
api_key = os.environ.get("MODEL_API_KEY")
# Create appropriate client based on configuration
if base_url:
client = RemoteModelClient(base_url, api_key, model_name)
else:
client = LocalModelClient(model_name)
return client
This standardized approach improves maintainability when supporting multiple AI backends and simplifies switching between different deployment configurations.
Follow consistent naming conventions in TypeScript to improve code clarity, type safety, and developer experience:
// Incorrect
type chainTypeName = "stuff" | "map_reduce";
// Correct
type ChainTypeName = "stuff" | "map_reduce";
unknown instead of any: When the type is truly not known, prefer unknown over any for better type safety.
// Incorrect - too permissive
function isBuiltinTool(tool: any)
// Correct - safer typing
function isBuiltinTool(tool: unknown)
// Incorrect
function createLoader(mode: string)
// Correct
type SearchMode = "subreddit" | "username";
function createLoader(mode: SearchMode)
// Incorrect
class GraphQLClientTool {
_endpoint: string;
}
// Correct
class GraphQLClientTool {
private endpoint: string;
}
model instead of modelName for consistency):
// Standardized
interface EmbeddingsParams {
model: string; // Not modelName
}
// Less precise
loaders: { [extension: string]: (path: string) => Loader }
// More precise
loaders: { [extension: `.${string}`]: (path: string) => Loader }
Simplify code by eliminating redundancy and unnecessary complexity. This improves readability, reduces potential bugs, and makes the codebase easier to maintain.
Some key practices to follow:
if (Object.keys(requestOptions).length === 0) { requestOptions = undefined; }
await when returning a promise.
```typescript
// Instead of this:
async function getData() {
return await fetchData();
}// Do this: async function getData() { return fetchData(); }
3. **Use concise array methods**: Many array methods have default parameters you can omit.
```typescript
// Instead of this:
return embeddings.flat(1);
// Do this:
return embeddings.flat();
constructor() { if (this.json) { // do something } } }
// Do this: class MyClass { constructor() { const json = false; if (json) { // do something } } }
Eliminating redundancy leads to cleaner, more maintainable code that's easier to review and less prone to errors.
---
## Configuration file consistency
<!-- source: lobehub/lobe-chat | topic: Configurations | language: Yaml | updated: 2025-05-26 -->
Ensure configuration values are consistent and properly coordinated across all related files (docker-compose, .env files, initialization scripts, workflows, etc.). Verify that port mappings, environment variables, and tokens don't conflict between files, and provide fallback configurations for critical settings.
Key practices:
- Cross-reference port assignments between docker-compose and .env files to prevent conflicts
- When adding new environment variables, update all relevant files (.env.example, init scripts, docker-compose)
- Provide fallback tokens/credentials (e.g., use GITHUB_TOKEN as fallback when PAT is not available)
- Test configuration changes locally to catch startup issues early
Example from discussions:
```yaml
# Bad: Port conflict
ports:
- '8000:8000' # Conflicts with CASDOOR_PORT=8000 in .env
# Good: Use environment variable consistently
ports:
- '${CASDOOR_PORT}:${CASDOOR_PORT}'
# Bad: No fallback
target_repo_token: ${{ secrets.PAT_FOR_SYNC }}
# Good: Provide fallback
target_repo_token: ${{ secrets.PAT_FOR_SYNC || secrets.GITHUB_TOKEN }}
Configuration documentation must accurately reflect implementation details and behavior. Ensure that:
Example - Incorrect:
const client = new MultiServerMCPClient({
mcpServers: {
'data-processor': {
command: 'python',
args: ['data_server.py']
}
}
});
Example - Correct:
const client = new MultiServerMCPClient({
'data-processor': {
command: 'python',
args: ['data_server.py']
}
});
When documenting configuration flags like useStandardContentBlocks, also include special case behavior (e.g., “audio content always uses standard content blocks regardless of this setting”).
Ensure all documentation is complete, well-formatted, and maximally useful for developers. This includes:
# Main Heading
## Subheading
- Bullet point
- Another bullet point
## Code Example
```typescript
const example = "properly formatted";
Install the [Oracle JavaScript client driver](https://node-oracledb.readthedocs.io/en/latest/) to get started:
```npm install oracledb```
| Parameter | Type | Default | Description |
| --------- | ---- | ------- | ----------- |
| `timeout` | number | 60000 | Timeout in milliseconds for the tool call |
| `signal` | AbortSignal | `undefined` | Optional AbortSignal to cancel the tool call |
Complete documentation improves developer experience, reduces questions, and facilitates faster onboarding.
Ensure all code examples in documentation are complete, accurate, and ready to run without modification. Since developers frequently copy and paste examples directly into their projects, include all required parameters and follow consistent patterns.
For example, when demonstrating object creation:
# Correct example with all required parameters
research_task = Task(
description="Research the latest AI developments",
expected_output="", # Include mandatory parameters even if empty
agent=researcher
)
Documentation structure should maintain consistent patterns across sections, explicitly listing required methods and parameters. This helps developers implement interfaces correctly and reduces the time spent debugging issues caused by incomplete examples.
Avoid using configuration values as implicit feature flags or logic triggers. Instead, validate configuration explicitly and make behavior predictable.
Configuration values should not be used to implicitly detect features or modes of operation, as this leads to false positives/negatives and confusing behavior. When configuration is required, validate it explicitly and fail fast with clear error messages.
Problems to avoid:
if self.config.per_instance_cost_limit == 0 and self.config.total_cost_limit == 0: # Local modelBetter approach:
# Instead of implicit detection
if self.config.per_instance_cost_limit == 0 and self.config.total_cost_limit == 0:
# Local model logic
# Use explicit configuration
if self.config.model_type == "local":
# Local model logic
# Validate required configuration explicitly
if self.args.model_name.startswith("deepseek"):
api_base_url = keys_config.get("DEEPSEEK_API_BASE_URL")
if not api_base_url:
raise ValueError("DEEPSEEK_API_BASE_URL must be specified for DeepSeek models")
Make configuration behavior predictable by validating requirements upfront and using explicit flags rather than inferring behavior from side effects of other configuration values.
Always leverage database-native data types and appropriate schema design to maximize performance and query capabilities. This includes:
// Instead of:
pref: JSON.stringify(this.pref)
// Prefer:
pref: { val: JSON.stringify(this.pref), type: oracledb.DB_TYPE_JSON }
// Instead of storing Date objects directly
doc.metadata.date = new Date()
// Store as ISO string for better compatibility
doc.metadata.date = new Date().toISOString()
// Better schema design with specific columns for important fields
await engine.pool.raw(`CREATE TABLE ${schemaName}.${tableName}(
id UUID PRIMARY KEY,
content TEXT NOT NULL,
created_date TIMESTAMP NOT NULL,
category VARCHAR(50) NOT NULL,
metadata JSON // Only for truly variable/unstructured data
)`);
This approach enables more efficient querying, better indexing capabilities, type validation at the database level, and allows you to leverage database-specific optimizations. Creating typed fields instead of dictionary-style complex types provides better type fidelity and enables richer filtering expressions like numeric/date range comparisons.
Names should clearly communicate their actual behavior and preserve sufficient context for meaningful identification. For functions with conditional behavior, use descriptive suffixes like _if_needed or _maybe to indicate optionality. For paths and identifiers, maintain enough context to ensure usability - avoid over-shortening that removes essential information.
Examples:
wait_for_indexing() for conditional waiting, use wait_for_indexing_if_needed()/home/user/work/dir1/file.ext to just file.ext, preserve context as dir1/file.extThis ensures that names serve as clear documentation of intent and maintain practical usability for developers and tools.
Always validate LLM capabilities before deployment and implement robust handling for unreliable responses. LLMs can vary significantly in capability and may return empty, invalid, or hallucinated responses that can break your application.
Implement capability testing with realistic prompts that match your actual usage patterns. Use simple knowledge tests to establish a minimum intelligence bar and filter out low-power models that struggle with basic instructions.
def _test_tool_calling_method(self, method: str) -> bool:
"""Test if a specific tool calling method works with the current LLM."""
try:
# Test with realistic prompt matching actual usage
test_message = HumanMessage(content='What is the capital of France? Respond with valid JSON.')
if method == 'raw':
response = self.llm.invoke([test_message])
# Validate both response format and basic intelligence
if not response or 'Paris' not in response.content:
return False
return True
except Exception:
return False
Always validate LLM outputs against original inputs to detect hallucination, and implement retry logic with fallback actions for empty or invalid responses:
if not model_output.action or all(action.model_dump() == {} for action in model_output.action):
logger.warning('Model returned empty action. Retrying...')
retry_messages = input_messages + [clarification_message]
model_output = await self.get_next_action(retry_messages)
if not model_output.action:
# Safe fallback action
action_instance = self.ActionModel(done={
'success': False,
'text': 'No next action returned by LLM!',
})
This approach significantly reduces support load from broken or low-capability models while ensuring your application remains functional even when LLMs behave unpredictably.
Before creating custom hooks, evaluate whether existing solutions or simpler patterns can address the need. Custom hooks should provide clear value beyond what’s available through established libraries, built-in React patterns, or direct component logic.
Ask these questions when reviewing custom hook implementations:
For example, instead of creating a custom useClickOutside hook, leverage existing solutions:
// Avoid: Custom implementation
export function useClickOutside<T extends HTMLElement = HTMLElement>(
ref: RefObject<T>,
callback: () => void
) {
// Custom click outside logic...
}
// Prefer: Existing library solution
import { useClickAway } from 'react-use';
// Use directly in component
useClickAway(ref, callback);
Custom hooks are valuable for encapsulating complex stateful logic, but avoid creating them when they merely wrap existing functionality without adding meaningful abstraction or reusability.
When integrating with AI model providers, implement defensive programming to handle API inconsistencies, bugs, and unexpected return types. AI provider libraries often have implementation bugs or return different types than documented, requiring robust error handling and type checking.
Key practices:
Example from LiteLLM tokenizer bug workaround:
def count_tokens(text: str) -> int:
enc = tokenizer_json["tokenizer"].encode(text)
if isinstance(enc, list):
return len(enc)
elif hasattr(enc, "ids"):
return len(enc.ids)
else:
raise TypeError(f"Unexpected return type from encode: {type(enc)}")
This approach ensures your AI model integrations remain robust even when underlying provider APIs have bugs or inconsistent behavior.
When handling null or undefined values, use modern JavaScript patterns to write more robust and maintainable code:
??) instead of logical OR (||) for defaults:
```javascript
// Good: Only falls back when value is null or undefined
this.endpointUrl = fields.endpointUrl ?? getEnvironmentVariable(“AZUREML_URL”);// Avoid: Will also replace empty strings, 0, and false this.endpointUrl = fields.endpointUrl || getEnvironmentVariable(“AZUREML_URL”);
2. Conditionally include properties in objects only when they exist:
```javascript
// Good: Only adds the property when content exists
const options = {
...otherOptions,
...(message.content != null ? { content: formatContent(message.content) } : {})
};
// Avoid: Passing undefined values to APIs
const options = {
...otherOptions,
audio: this.audio // might be undefined
};
===, !==) for null checks:
// Good: Clear intent, checks for both null and undefined
if (documents === null || documents === undefined) {
// Handle the case
}
// Or more concisely:
if (documents == null) {
// Handle the case
}
// Avoid: Oversimplified check if (!config.client && !endpoint && !key) { // This will only throw if ALL are missing }
These patterns help prevent subtle bugs and make your code's intent clearer to other developers.
---
## Avoid hard-coded configuration
<!-- source: openai/codex | topic: Configurations | language: Shell | updated: 2025-05-16 -->
Make scripts and applications flexible by avoiding hard-coded configuration values. Instead, allow users to provide configuration through command-line flags, environment variables, or configuration files. When updating scripts to use configurable parameters:
1. Prefer explicit flag-based interfaces over positional arguments
2. Use descriptive names for flags, especially those with security implications (e.g., `--dangerously-allow-network-outbound`)
3. Validate configuration values before use to prevent errors
4. Maintain backward compatibility when possible
5. Include helpful usage documentation
Example:
```bash
#!/usr/bin/env bash
# Parse optional flags with descriptive names
while [ "$#" -gt 0 ]; do
case "$1" in
--dangerously-allow-network-outbound)
ALLOW_OUTBOUND=true
shift
;;
--work_dir)
if [ -z "$2" ]; then
echo "Error: --work_dir flag provided but no directory specified."
exit 1
fi
WORK_DIR="$2"
shift 2
;;
-h|--help)
echo "Usage: $(basename "$0") [--dangerously-allow-network-outbound] [--work_dir directory]"
exit 0
;;
*)
# Handle other arguments or commands
break
;;
esac
done
# Validate environment variables before use
if [ -z "$ALLOWED_DOMAINS" ]; then
echo "Error: ALLOWED_DOMAINS is empty."
exit 1
fi
Always explicitly declare environment variables in configuration files, even when they have default values. Use consistent naming conventions with appropriate prefixes for related variables, and clearly document when each variable is required versus optional.
This practice prevents configuration confusion and makes deployment requirements transparent. For example, instead of relying on implicit defaults, explicitly set values like NEXT_PUBLIC_ENABLE_NEXT_AUTH=0 in environment files. Use consistent prefixes such as AUTH_ for authentication-related variables, and provide clear documentation about when variables are needed (e.g., “necessary for self-hosting with Docker” vs “optional for most users”).
# Good: Explicit declaration with clear naming
NEXT_PUBLIC_ENABLE_NEXT_AUTH=0
AUTH_GITHUB_CLIENT_ID=your_client_id
AUTH_GITHUB_CLIENT_SECRET=your_secret
# Bad: Missing explicit declaration, inconsistent naming
# NEXT_PUBLIC_ENABLE_NEXT_AUTH (relies on default)
GITHUB_CLIENT_ID=your_client_id # Missing AUTH_ prefix
Document each variable’s purpose and requirements in configuration guides, using callouts or tables to indicate when specific variables are mandatory for different deployment scenarios.
Ensure algorithmic implementations use correct patterns, handle edge cases gracefully, and avoid silent failures. This includes using proper mathematical functions, correct object access methods, and robust error handling for each operation.
Key principles:
np.log2() instead of np.log() when the algorithm specifically requires base-2 logarithmsStatus(value) for value-based lookup instead of Status[value] which expects namesExample of robust per-item processing:
def _copy_tools(self, tools):
copied_tools = []
for tool in tools:
try:
copied_tools.append(copy.deepcopy(tool))
except Exception as e:
logger.warning(f"Could not deep copy tool {tool}, using shallow copy: {e}")
copied_tools.append(copy.copy(tool))
return copied_tools
Example of correct enum handling:
# Correct: restore enum from value
parsed_value = Status(value) # where value is "in_progress"
# Incorrect: lookup by name when you have value
parsed_value = Status[value] # throws KeyError
This approach prevents algorithmic errors that can lead to silent failures, incorrect results, or runtime exceptions in production code.
Always use the established logging framework instead of console.log or ad-hoc logging approaches. This ensures consistent log formatting, proper log levels, and better log management across the application.
When logging errors, include contextual information like error traces, messages, and auxiliary data to make logs more informative for debugging. For components that need logging capabilities, inherit or inject the logger from the main application rather than creating separate logging mechanisms.
Example of what to avoid:
console.log(options.messages);
console.log(tree);
Example of proper structured logging:
this.logger({
category: "debug",
message: "Processing options messages",
auxiliary: { messageCount: options.messages.length }
});
this.stagehandLogger.error(
"The browser context is undefined. This means the CDP connection to the browser failed"
);
This approach provides better log filtering, formatting, and integration with log management systems while maintaining consistency across the codebase.
Always provide clear feedback when operations fail, even when continuing with fallbacks or alternative approaches. Silent failures make debugging extremely difficult and can lead to unexpected behavior in production systems.
Key practices:
Example of proper optional dependency handling:
# Good - defer error until usage
try:
import optional_library
except ImportError:
optional_library = None
def use_optional_feature():
if optional_library is None:
raise ImportError("optional_library is required for this feature. Install with: pip install optional_library")
return optional_library.do_something()
# Bad - fails at import time
import optional_library # This breaks if not installed
Example of proper fallback with feedback:
# Good - inform about fallback
try:
result = primary_operation()
except SpecificError as e:
logger.warning(f"Primary operation failed: {e}. Falling back to alternative.")
result = fallback_operation()
# Bad - silent fallback
try:
result = primary_operation()
except:
result = fallback_operation() # No indication why fallback was used
This approach ensures that failures are visible to developers and operators, making systems more maintainable and debuggable.
Use full commit hashes instead of version tags when referencing third-party GitHub Actions in workflows to prevent unexpected behavior changes if the action is modified at its source. This ensures reproducible builds and improves security by protecting against supply chain attacks.
For GitHub’s own first-party actions, using semantic versioning tags (like @v4) is acceptable since they are widely used and well-maintained, making it easier to identify canonical versions.
Example:
steps:
# Third-party actions: Use full commit hash
- name: Annotate locations with typos
uses: codespell-project/codespell-problem-matcher@a8ce06949d771ee07807e8ce2c9b873f906a9fc2 # v1
- name: Codespell
uses: codespell-project/actions-codespell@94e0a8e0b7e2a42a1e1223cc80b4c150a38a0e1e # v2
# GitHub first-party actions: Semantic versioning is acceptable
- name: Checkout
uses: actions/checkout@v4
This practice helps ensure that your CI/CD pipelines remain stable and secure over time, and allows for explicit updating of dependencies when desired rather than automatically adopting potentially breaking changes.
Implement strict security controls in continuous integration and deployment workflows:
# Separate high-privilege workflows (e.g., update-nix-hash.yml) from regular CI workflows
permissions:
contents: write # Clearly visible elevated permission
if: github.event_name == 'push' && github.ref == 'refs/heads/main')Implementing these practices prevents supply chain attacks and reduces the risk of compromised workflows affecting your repository.
Always specify explicit versions for testing frameworks and tools to ensure reproducible test environments across different deployment contexts. Avoid installing testing dependencies with implicit “latest” versions, which can lead to inconsistent test behavior and difficult-to-debug failures.
Use environment variables or extract versions from dependency manifests rather than hard-coding versions directly in installation commands:
# Option 1: Using environment variables
RUN pip install playwright==$PLAYWRIGHT_VERSION
# Option 2: Extract from dependency manifest
RUN PLAYWRIGHT_VERSION=$(grep -oP 'playwright>=\K[0-9.]+' pyproject.toml) \
&& pip install playwright==$PLAYWRIGHT_VERSION
This practice is especially critical in containerized environments where test dependencies need to remain consistent across development, CI/CD, and production testing scenarios. Version pinning prevents unexpected test failures caused by breaking changes in testing framework updates and ensures that test results are reproducible across different environments and time periods.
When using Vitest mocking, avoid multiple vi.mock calls for the same module within a single test file, as mock calls are hoisted and can interfere with each other. Instead, organize tests requiring different mock configurations into separate test files or test suites with proper setup/teardown.
The issue arises because vi.mock calls are hoisted to the top of the file, making it impossible to have different mock implementations for different test scenarios in the same file. This can cause tests to break unexpectedly when mock configurations conflict.
Problematic approach:
// This won't work as expected - both mocks target the same module
vi.mock("../../../context/ExtensionStateContext", () => ({
useExtensionState: vi.fn(() => ({ apiProvider: "openai" }))
}))
vi.mock("../../../context/ExtensionStateContext", () => ({
useExtensionState: vi.fn(() => ({ apiProvider: "nebius" }))
}))
Better approach:
beforeEach/afterEach to modify mock return values within the same mock setupThis ensures test isolation and prevents one test’s mock configuration from breaking others.
Always thoroughly test API features and endpoints before documenting them, especially when integrating with third-party services. Documentation should accurately reflect the actual behavior of the API, including:
For error documentation, focus on specific causes rather than general descriptions:
// DON'T: Use vague descriptions
// "APICallError occurs when there's an issue during an API call"
// DO: Be specific about error causes
// "APICallError occurs when a provider API returns an error response,
// typically due to invalid message structure. Always check the provider's
// error message for specific resolution steps."
For third-party integrations, test thoroughly and document any limitations:
// Example: Adding appropriate warnings for feature limitations
if (isGoogleProvider && options.includeThoughts) {
console.warn('includeThoughts is not fully supported in all Google Generative AI models.');
}
For code examples, ensure they are practical and executable:
// DON'T: Use abstract placeholders without explanation
const { transcript } = await generateTranscript({
model: openai.transcription('whisper-1'),
audio: audioData, // What is audioData?
});
// DO: Provide complete, executable examples
import fs from 'fs/promises';
const audioData = await fs.readFile('./sample-audio.mp3');
const { transcript } = await generateTranscript({
model: openai.transcription('whisper-1'),
audio: audioData,
});
This standard ensures that developers can rely on your documentation to accurately understand how to use your API properly, reducing confusion and support issues.
Avoid unnecessary duplication and bloat in Docker layers by trusting base images to provide standard tools and using appropriate installation methods. Instead of upgrading pip when the base image already provides it, trust the image’s version to prevent duplicate copies across layers. When installing application code, use editable installs to avoid creating duplicate copies of the codebase in different layers.
Example of problematic approach:
RUN pip install --upgrade pip \
&& pip install .
Preferred approach:
# Trust base image pip version, use editable install
RUN pip install -e .
This reduces image size, build time, and layer complexity while maintaining the same functionality. Apply this principle to other tools and dependencies - only install what’s not already provided by the base image.
When designing systems that handle sensitive operations, always default to the most secure behavior rather than prioritizing convenience. This practice applies to error handling, execution environments, and security-critical fallbacks.
Key principles to follow:
Sanitize error responses: Never expose internal exception details or stack traces in API responses that could reveal implementation details to potential attackers.
Require explicit opt-in for reduced security: Don’t silently fall back to less secure modes of operation; require explicit configuration through environment variables or parameters.
Log security-relevant decisions: Ensure security-related fallbacks are clearly logged for monitoring and debugging.
Example of insecure error handling:
except Exception as e:
return JSONResponse(
content=JSONRPCResponse(
id=request_id,
error=InternalError(data=str(e)), # Exposes potentially sensitive details
),
status_code=500,
)
Secure implementation:
except Exception as e:
# Log complete details for internal use
self.logger.exception(f"Error handling {method} request")
# Return sanitized response to external users
return JSONResponse(
content=JSONRPCResponse(
id=request_id,
error=InternalError(data="An internal server error occurred"),
),
status_code=500,
)
Example of insecure fallback:
unsafe_mode = not self.check_docker_available()
# Silently proceeds with unsafe execution
Secure implementation:
if not self.check_docker_available():
if os.getenv("CREWAI_GUARDRAIL_EXECUTION_MODE") == "allow_unsafe":
self.logger.warning("Docker unavailable. Falling back to unsafe execution mode.")
self.unsafe_mode = True
else:
raise SecurityError("Cannot execute code safely. Docker unavailable and unsafe execution not explicitly enabled.")
Maintain consistent naming patterns and parameter structures across AI provider implementations. This makes the SDK more intuitive and reduces developer friction when switching between different AI models or providers.
Key practices:
.response instead of .rawResponse for provider API responsesproviderOptions parameterExample:
// Preferred approach
const { response } = await embed({
providerOptions: {
// Provider-specific options here
}
});
// Instead of
const { rawResponse } = await embed({
// Mixing provider-specific options at the top level
});
When adding examples for AI providers, always verify that model identifiers are valid for the specific provider (e.g., using ‘scribe_v1’ for ElevenLabs transcription models rather than invalid identifiers).
Standardize version management across multi-crate Rust projects by using workspace versioning. This reduces duplication and ensures consistency across all crates in your project.
Implementation:
[workspace]
version = "0.1.0"
[package]
name = "your-crate-name"
version = { workspace = true }
This approach centralizes version management, making it easier to release coordinated updates across all crates while maintaining a consistent configuration structure.
When configuring authentication in CI/CD workflows, prefer using tokens over passwords for enhanced security. Tokens can be scoped with specific permissions, rotated more easily, and provide better audit trails compared to passwords. This is particularly important for service-to-service authentication where credentials are stored as secrets.
For Docker Hub authentication in GitHub Actions, use a personal access token instead of your account password:
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_TOKEN }} # Use token instead of password
Even when official documentation shows password usage, prioritize token-based authentication as it follows security best practices and reduces the risk of credential compromise.
Structure CI workflows to minimize execution time and resource usage through strategic job organization, caching, and elimination of redundant operations.
Key optimization strategies:
Example of optimized job structure:
jobs:
# Fast parallel checks (each ~20sec)
syntax-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv run ruff check --no-fix --select PLE
format-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv run ruff format
- run: uv run pre-commit run --all-files
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv run pyright
# Build once, test across matrix
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
- run: uv build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
test-import:
needs: build
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.11", "3.12", "3.13"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- run: python -c "import browser_use; print('Success!')"
This approach reduces total CI time from sequential execution to parallel execution, with all checks completing in under 30 seconds instead of several minutes.
Structure documentation to be approachable for beginners while remaining comprehensive for all users. Keep main pages focused on common use cases with simplified examples, and move advanced configurations to separate, linked sections. When documenting features, start with basic usage before detailing exceptions or edge cases.
For example, instead of including complex configuration options in introductory documentation:
{
"embeddingsProvider": {
"provider": "ollama",
"embeddingPrefixes": [
// complex configuration...
]
}
}
Present a simpler initial example:
{
"embeddingsProvider": {
"provider": "ollama",
"model": "nomic-embed-text"
}
}
With a clear link to advanced configuration options for users who need them. This progressive disclosure approach ensures new users aren’t overwhelmed while giving experienced users access to the depth they need.
Test scenarios and steps should use specific, descriptive language that clearly communicates what is being tested and what behavior is expected. Avoid vague or ambiguous terms that leave room for interpretation.
When writing test scenarios, use descriptive names that specify the exact conditions and expected outcomes rather than generic phrases. For test steps, explicitly define all inputs and conditions rather than using undefined references.
Examples of improvements:
Use: “The agent correctly chooses to call the right overlapping tool based on glossary”
This ensures that anyone reading the tests can understand exactly what scenario is being tested without having to make assumptions about undefined or vague references.
Implement telemetry collection strategically to ensure system reliability and meaningful data capture. Place telemetry calls where relevant context is available, use non-blocking patterns for time-sensitive operations, and avoid unnecessary abstraction.
Key principles:
Example implementation:
// Good: Periodic collection with non-blocking pattern
const thirtyMinutes = 30 * 60 * 1000
telemetryIntervalId = setInterval(() => {
// Fire-and-forget, log potential errors but don't block
void telemetryService.sendCollectedEvents().catch((error) => {
Logger.error("Error sending periodic telemetry:", error)
})
}, thirtyMinutes)
// Good: Capture at the point where context is available
const options = parsePartialArrayString(optionsRaw || "[]")
this.lastOptionsCount = options.length
// Good: Direct usage instead of unnecessary abstraction
telemetryService.captureTaskRestarted(this.taskId, apiConfiguration.apiProvider)
When building scripts or applications that require user authentication, avoid automating interactive authentication processes that could cause system instability or security issues. Instead, check authentication status programmatically and delegate the actual authentication to the user.
Interactive authentication commands (like login flows) can cause console freezing, unpredictable behavior, or security vulnerabilities when executed programmatically. The safer approach is to verify authentication status and provide clear instructions for users to authenticate themselves.
Example implementation:
const checkGitHubAuth = async () => {
try {
execSync("gh auth status", { stdio: "ignore" })
return true
} catch (err) {
console.log("\nGitHub authentication required.")
console.log("\nPlease run the following command in your terminal to authenticate:")
console.log("\n gh auth login\n")
return false
}
}
This approach maintains security boundaries, prevents system issues, and ensures users maintain control over their authentication credentials while still enabling automated workflows to function properly.
When designing APIs that support multiple providers or service integrations, implement consistent patterns for handling provider-specific options. This includes proper validation, separation of request vs. non-request options, and clear type definitions.
Key practices:
// Good practice: Extract non-request options before API calls
const { pollIntervalMillis, maxPollAttempts, ...providerRequestOptions } =
providerOptions.luma ?? {};
// Good practice: Use standardized validation
const openaiOptions = parseProviderOptions({
provider: 'openai',
providerOptions,
schema: openaiProviderOptionsSchema,
});
// Good practice: Well-documented provider option types
export type GladiaTranscriptionInitiateAPITypes = {
/** URL to a Gladia file or to an external audio or video file */
audio_url: string;
/** [Alpha] Context to feed the transcription model with for better accuracy */
context_prompt?: string;
// Additional well-documented parameters...
};
This approach ensures type safety, prevents sending unnecessary options to external APIs, and makes your code more maintainable as you add support for new providers or update existing integrations.
When designing API functions with multiple parameters, consolidate optional or related parameters into a single options object to improve extensibility and maintainability. This pattern prevents function signatures from becoming unwieldy and allows for easier future parameter additions without breaking changes.
Key principles:
Example of good parameter consolidation:
// Before: Multiple separate parameters
export const QwenAIStream = (
stream: Stream<OpenAI.ChatCompletionChunk>,
callbacks?: ChatStreamCallbacks,
inputStartAt?: number,
)
// After: Consolidated into options object
export const QwenAIStream = (
stream: Stream<OpenAI.ChatCompletionChunk>,
options?: {
callbacks?: ChatStreamCallbacks;
inputStartAt?: number;
}
)
Example of using utility functions:
// Before: Manual URL construction
const avatarUrl = fileEnv.S3_PUBLIC_DOMAIN + '/' + filePath;
// After: Using utility function
const avatarUrl = await ctx.fileService.getFullFileUrl(filePath);
// Before: Manual URL joining
endpointUrl: instance.baseURL + '/' + payload.model
// After: Using urlJoin utility
endpointUrl: urlJoin(instance.baseURL, payload.model)
This approach makes APIs more maintainable, reduces the likelihood of bugs from manual implementations, and provides a clear upgrade path for future enhancements.
Maintain consistent code style by using and respecting the project’s established formatting tools and patterns. Run linters and formatters (pnpm run format, pnpm run lint) before committing code. Organize logical expressions for clarity and consistency, and prefer language constructs that work well with static analysis tools.
For example, maintain symmetry in related conditional blocks:
// GOOD: Organize conditions symmetrically and logically
if (
(key["meta"] || key["ctrl"] || key["alt"]) &&
(key["backspace"] || input === "\x7f") &&
!key["shift"]
) {
this.deleteWordLeft();
}
// AVOID: Asymmetrical or nested conditions that are harder to parse
if (
(key["meta"] || key["ctrl"] || key["alt"]) &&
(key["backspace"] || input === "\x7f" || (key["delete"] && !key["shift"]))
) {
this.deleteWordLeft();
}
Use language constructs that leverage static analysis, like switch statements for exhaustive checking of enum values, even when it might seem easier to convert to if/else statements. This ensures that when new enum variants are added, existing code will be flagged for updates.
Implement error handling with clear intent and proper propagation. Follow these principles:
Example of proper error handling structure:
try:
if self.max_execution_time is not None:
if not isinstance(self.max_execution_time, int) or self.max_execution_time <= 0:
raise ValueError("Max Execution time must be a positive integer greater than zero")
result = self._execute_with_timeout(task_prompt, task, self.max_execution_time)
else:
result = self._execute_without_timeout(task_prompt, task)
except TimeoutError as e:
error = f"Task '{task.description}' execution timed out after {self.max_execution_time} seconds. Consider increasing max_execution_time or optimizing the task."
crewai_event_bus.emit(
self,
event=AgentExecutionErrorEvent(
agent=self,
task=task,
error=error
)
)
raise TimeoutError(error)
This pattern ensures:
When designing AI components and tools, use domain-specific terminology and provide clear interface documentation to enhance usability and integration. This includes:
Use precise, domain-specific naming that clearly indicates the component’s purpose and functionality in the AI ecosystem. For example, prefer LLMGuardrail over generic terms like Validator when the component specifically handles language model outputs.
Document how AI agents and LLMs will interact with your tools, including expected inputs, outputs, and parameter definitions. This helps other developers understand how the AI will interpret and use the tool.
Provide complete usage examples that demonstrate real-world integration patterns.
Example:
# Good practice with clear naming and documentation
from crewai import Task
from crewai.llm import LLM
task = Task(
description="Generate JSON data",
expected_output="Valid JSON object",
guardrail=LLMGuardrail( # Specific name indicates it works with LLMs
instructions="Ensure the response is a valid JSON object",
examples=[{"valid": {"key": "value"}}]
)
)
# Example showing tool integration with clear documentation of parameters
from crewai_tools import AISearchTool # Name indicates AI-specific functionality
# Document how the AI will use this tool
search_tool = AISearchTool(
name="Web Search", # Clear name for AI to reference
description="Search the web for up-to-date information on a given topic",
input_schema={"query": "The search term or question to look up online"}
)
agent = Agent(
role="Research Analyst",
goal="Provide up-to-date market analysis",
tools=[search_tool]
)
Clear interfaces improve maintainability, make your code more intuitive for other developers, and help language models better understand how to interact with your components.
Maintain clear code organization by placing code in appropriate files, directories, and modules. Respect module boundaries and create logical directory structures that reflect the code’s purpose and domain.
Key principles:
StagehandInitResult to types/evals.ts)lib/a11y for accessibility utilities)dist, not lib)prompts.ts)Example of proper organization:
// Before: accessibility functions mixed in handlers
// lib/handlers/observeHandler.ts
type AccessibilityNode = { ... }
function formatSimplifiedTree() { ... }
// After: dedicated accessibility module
// lib/a11y/utils.ts
type AccessibilityNode = { ... }
function formatSimplifiedTree() { ... }
This approach improves code discoverability, reduces coupling between modules, and makes the codebase easier to navigate and maintain.
When implementing algorithms that involve pattern matching or data parsing, ensure robustness across all edge cases and clearly document the algorithm’s behavior. This is particularly important for:
// Instead of returning any partial match:
const possibleEnumValues = enumValues.filter(enumValue =>
enumValue.startsWith(result)
);
// Consider uniqueness in your algorithm:
if (possibleEnumValues.length > 1) {
// Handle ambiguous case - either return only the partial result
// or require a complete match
return { partial: result };
} else if (possibleEnumValues.length === 1) {
// Return the full value when there's only one possible match
return { complete: possibleEnumValues[0] };
}
// Check for format-specific headers before pattern matching
const stripMetadata = (data: Uint8Array) => {
// Detect specific header patterns (like ID3 for MP3)
if (data[0] === 0x49 && data[1] === 0x44 && data[2] === 0x33) {
// Calculate header size and return data without header
const headerSize = calculateHeaderSize(data);
return data.slice(headerSize);
}
return data; // No metadata found
};
// Then perform format detection on clean data
const detectedFormat = detectFormat(stripMetadata(rawData));
// Incorrect: iterating over empty/wrong object
for (const key in emptyObject) { /* ... */ }
// Correct: iterate over the object containing actual data
for (const key in dataObject) {
if (dataObject[key] !== undefined) {
processedData[key] = dataObject[key];
}
}
Always test pattern matching algorithms with comprehensive test cases covering edge cases like empty inputs, partial matches, and format variations.
Design CI/CD workflows for long-term maintainability by using consolidated commands and extracting reusable components. Instead of listing individual build steps that may change over time, prefer consolidated npm scripts like npm run pretest that encapsulate the full build process. This approach reduces the need to update workflows when underlying build requirements change. For complex inline logic, extract functionality into custom GitHub Actions rather than embedding lengthy scripts directly in workflow files.
Example of maintainable approach:
# Preferred: Uses consolidated command
- name: Build Tests and Extension
run: npm run pretest
# Instead of: Individual commands that require updates
- name: Check Types
run: npm run check-types
- name: Lint
run: npm run lint
- name: Build Extension
run: npm run compile
For reusable logic, create custom actions instead of inline scripts to improve readability and enable reuse across workflows.
Use specific and consistent naming conventions when referencing AI services, models, and their parameters throughout your codebase. Always include the full provider name (e.g., “AzureOpenAI” instead of just “Azure”) to clearly distinguish between different AI services and avoid ambiguity.
For variables, parameters, and properties related to AI services:
Example:
// Incorrect - ambiguous naming
const azureParams = `{
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"]
}`;
// Correct - specific and consistent naming
const azureOpenAIParams = `{
azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
openai_api_version=os.environ["AZURE_OPENAI_API_VERSION"]
}`;
// Component property should also use the specific name
@property {boolean} [hideAzureOpenAI] - Whether or not to hide Microsoft Azure OpenAI chat model.
This practice improves code readability, reduces confusion when working with multiple AI services, and makes maintenance easier, especially as you integrate additional AI providers in the future.
Always use the correct syntax for accessing environment variables based on the target platform. In JavaScript/Node.js environments, use process.env.VARIABLE_NAME instead of syntaxes from other languages (e.g., Python’s os.environ).
Example:
// Incorrect - Using Python syntax in JavaScript
const config = {
azure_endpoint: os.environ["AZURE_OPENAI_ENDPOINT"],
azure_deployment: os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
openai_api_version: os.environ["AZURE_OPENAI_API_VERSION"]
};
// Correct - Using JavaScript syntax
const config = {
azure_endpoint: process.env.AZURE_OPENAI_ENDPOINT,
azure_deployment: process.env.AZURE_OPENAI_DEPLOYMENT_NAME,
openai_api_version: process.env.AZURE_OPENAI_API_VERSION
};
For platform-specific configurations, consider using appropriate file formats (like .mdx for Node-specific code) or implement automatic import methods that work across environments to improve compatibility.
Structure test suites into clear, logical categories and run them as separate CI jobs for better parallelization, maintainability, and failure identification. This approach makes it easier to understand test failures, enables targeted testing, and improves CI performance through parallel execution.
Organize tests by functional area or technology stack, such as:
Example CI matrix configuration:
strategy:
matrix:
test:
- browser/patchright
- browser/user_binary
- browser/remote_cdp
- models/openai
- models/google
- models/anthropic
# TODO: keep adding more in the future
# - models/azure
# - models/deepseek
# - functionality/click
# - functionality/tabs
This structure allows teams to easily add new test categories, run specific test subsets, and quickly identify which area of the codebase has issues when tests fail.
When scheduling asynchronous operations in concurrent environments, always verify the system state hasn’t changed before executing critical operations to prevent race conditions. This is especially important in interactive applications where user actions (like cancellations) might occur between the time an operation is scheduled and when it executes.
To implement this pattern:
Example:
// Instead of this:
setTimeout(() => {
this.onItem(item);
staged[idx] = undefined;
}, delay);
// Do this:
setTimeout(() => {
// Double-check cancellation state right before executing
if (
thisGeneration === this.generation &&
!this.canceled &&
!this.hardAbort.signal.aborted
) {
this.onItem(item);
staged[idx] = undefined;
}
}, delay);
This pattern helps maintain consistency between internal state and UI, prevents “ghost” operations from occurring after cancellation, and makes your concurrent code more robust against race conditions.
Avoid hard-coding model names and provider-specific configurations throughout the codebase. Instead, implement flexible model selection patterns that support runtime configuration and consistent naming conventions across different AI providers.
Key practices:
Example of problematic pattern:
// Bad: Hard-coded model name
const response = await client.chat.completions.create({
model: "gpt-4o", // Hard-coded
messages: [...],
});
// Bad: Repetitive model specification
await stagehand.act({ action: "start game", model_name: "gpt-4o" });
await stagehand.extract({ instruction: "get price", model_name: "gpt-4o" });
Example of improved pattern:
// Good: Configurable with defaults
class Stagehand {
constructor(private defaultModel: string = "gpt-4o") {}
async act(options: { action: string; modelName?: string }) {
const model = options.modelName || this.defaultModel;
// Use configured model
}
}
// Good: Consistent provider naming
const modelToProviderMap: { [key in AvailableModel]: ModelProvider } = {
"cerebras-llama-3.3-70b": "cerebras",
"openai-gpt-4o": "openai",
};
This approach improves maintainability, reduces duplication, and makes model selection more flexible for different deployment scenarios.
When modifying existing APIs, maintain backward compatibility by implementing changes in a non-breaking way. Use method overloading, optional parameters, or deprecation notices rather than direct breaking changes.
Example of proper API evolution:
// Instead of changing existing interface:
interface DeleteParams {
ids: string[];
}
// Add overloaded method signatures:
class Store {
// Original method
async delete(ids: string[]): Promise<void>;
// New overload with expanded functionality
async delete(params: DeleteParams): Promise<void>;
// Implementation handling both cases
async delete(idsOrParams: string[] | DeleteParams): Promise<void> {
if (Array.isArray(idsOrParams)) {
// Handle legacy case
return this.deleteByIds(idsOrParams);
}
// Handle new case
return this.deleteWithParams(idsOrParams);
}
}
// For deprecations, add clear notices:
/** @deprecated Use newMethod() instead. Will be removed in next major version. */
This approach allows gradual migration to new patterns while maintaining existing integrations. When deprecating functionality, provide clear migration paths and timeline in documentation.
Always use specific, descriptive names for identifiers rather than generic terms. Names should clearly indicate their purpose and context, making code more readable and self-documenting. This applies to variables, parameters, types, and files.
Examples:
mcpServers instead of servers to include contextstoreResponses over store to clarify the parameter’s purposeUpdateState instead of generic Stateupdate-state.json, .codex.env)This practice reduces cognitive load for other developers, improves maintainability, and helps prevent confusion or misuse of code elements. The additional verbosity is well worth the clarity it provides.
Allow errors to bubble up to their appropriate handling layers rather than catching them prematurely. Catching errors at incorrect levels can prevent proper error handling, recovery mechanisms, and specialized handlers (like rate limiting logic) from functioning as intended.
When designing error handling, consider:
// Poor practice - catching errors too early without proper handling
try {
await performOperation();
} catch (error) {
console.error('Operation failed:', error);
// No meaningful recovery or proper error propagation
}
// Better practice - let errors propagate to appropriate handlers
// In component code:
await performOperation(); // No try/catch here
// In higher-level error handling layer:
try {
await executeComponentCode();
} catch (error) {
if (error instanceof RateLimitError) {
return await retryWithBackoff();
} else if (error instanceof NetworkError) {
// Specialized handling for network issues
} else {
// Log and propagate further if needed
logger.error('Unhandled error:', error);
throw error;
}
}
This approach creates a cleaner separation of concerns, centralizes error handling logic, and ensures errors are handled at the most appropriate level.
Always wrap asynchronous operations in try-catch blocks to prevent unhandled promise rejections and provide graceful error recovery. This is especially important for browser APIs that may fail due to user permissions, network issues, or browser compatibility.
When an async operation fails, log the error appropriately and implement fallback behavior or user-friendly error messages. Avoid letting async operations fail silently, as this can lead to confusing user experiences.
Example of proper async error handling:
const handleCopyCode = async () => {
try {
await navigator.clipboard.writeText(code)
} catch (err) {
console.error('Copy failed', err)
// Optional: Show user-friendly error message
}
}
For operations that may fail but have acceptable fallback behavior, handle errors gracefully by returning default values and informing users when appropriate, such as showing “Chrome not detected” messages when browser detection fails.
When making code organization decisions, consider the broader impact beyond just eliminating duplication or following patterns. Sometimes a slightly less “clean” solution is preferable when it preserves type safety, maintains clear class responsibilities, or avoids exposing unnecessary implementation details.
Key considerations:
Example: Instead of extracting common code that would lose TypeScript type information:
// Prefer this (preserves type safety)
if (this.#protocol === "sse") {
this.#transport = new McpSSETransport(() => this.getWebSocket());
await this.server.connect(this.#transport);
} else if (this.#protocol === "streamable-http") {
this.#transport = new McpStreamableHttpTransport(/*...*/);
await this.server.connect(this.#transport);
}
// Over this (loses type information, requires assertions)
this.#transport = this.#protocol === "sse"
? new McpSSETransport(/*...*/)
: new McpStreamableHttpTransport(/*...*/);
await this.server.connect(this.#transport!); // Type assertion needed
The goal is maintainable code that serves developers well, not just adherence to abstract principles.
Always validate network connection types, required parameters, and protocol-specific headers before processing requests. This prevents runtime errors and ensures proper connection handling across different network protocols.
For WebSocket connections, verify the Upgrade header and required parameters:
// Validate WebSocket upgrade request
if (request.headers.get("Upgrade") !== "websocket") {
return new Response("Expected WebSocket Upgrade request", {
status: 400,
});
}
// Validate required parameters
const url = new URL(request.url);
const sessionId = url.searchParams.get("sessionId");
if (!sessionId) {
return new Response("Missing sessionId", { status: 400 });
}
Use URL paths to distinguish between different protocols and route accordingly:
const path = url.pathname;
switch (path) {
case "/sse": {
// Handle SSE protocol
break;
}
case "/websocket": {
// Handle WebSocket protocol
break;
}
}
Consider implementing connection limits and state management to prevent issues with multiple concurrent connections when your system expects only one active connection per session.
Ensure configuration specifications (such as version requirements, environment settings, and tool declarations) are consistent and not duplicated across project files. Redundant or contradictory configuration declarations create maintenance issues and confusion.
For example, instead of declaring the same tool in multiple places:
# agents.yaml
tools:
- SerperDevTool # Don't declare here if also declared in crew.py
# crew.py
# Declare tools in a single location
tools = [SerperDevTool()]
Similarly, ensure version specifications in documentation accurately reflect actual compatibility:
# README.md
Ensure you have Python >=3.10 <3.12 installed on your system.
When the project actually supports Python 3.12, this should be correctly documented as:
# README.md
Ensure you have Python >=3.10 <=3.12 installed on your system.
When configuring command whitelists for auto-approval, include only commands with limited capabilities that cannot be exploited for malicious purposes. Powerful tools like text editors (e.g., vim) should be avoided as they provide broad system access and functionality that could introduce security vulnerabilities if auto-approved.
Instead, prefer commands with specific, limited functionality such as nl (number lines). Evaluate each command for its potential security impact before adding it to the whitelist.
Example:
# Recommended
commandWhitelist:
- "nl"
- "cat"
- "grep"
# Not recommended
commandWhitelist:
- "vim" # Avoid - provides too much functionality and system access
- "bash" # Avoid - allows arbitrary command execution
Always ask: “What’s the worst that could happen if this command is automatically approved and executed?” If the answer involves potential system compromise or data exposure, don’t whitelist it.
Configuration files should be self-explanatory and maintainable by including explicit version constraints and explanatory comments for non-obvious choices. This prevents future confusion and ensures reproducible environments.
For dependencies, always specify version constraints rather than leaving them open-ended:
dependencies = [
"anyio>=4.9.0", # Not just "anyio"
]
For configuration choices that might seem unusual, add comments explaining the reasoning:
[tool.ruff.lint]
select = ["ASYNC", "E", "F", "I", "PLE"]
ignore = ["ASYNC109", "E101", "E402", "E501", "F841", "E731"] # TODO: determine if adding timeouts to all the unbounded async functions is needed / worth-it so we can un-ignore ASYNC109
This practice helps future maintainers understand the rationale behind configuration decisions and makes it easier to revisit choices when requirements change.
Ensure consistent patterns and configurations across all AI model providers to maintain code maintainability and scalability. This includes providing proper default configurations for all providers and minimizing provider-specific conditional logic that can become unwieldy as more AI models are integrated.
Key practices:
Example of inconsistent approach to avoid:
// Avoid provider-specific logic scattered throughout
const maxTokens = apiConfiguration?.apiProvider === "gemini"
? geminiModels[geminiDefaultModelId].maxTokens
: anthropicModels["claude-3-7-sonnet-20250219"].maxTokens
// Instead, use a unified approach
case "sambanova":
return getProviderData(sambanovaModels, sambanovaDefaultModelId) // Always provide default
This approach reduces technical debt and makes the codebase more maintainable as the number of supported AI providers grows.
Always verify algorithms work correctly across edge cases and boundary conditions through concrete examples and mathematical validation. Pay special attention to preventing infinite recursion and ensuring mathematical formulas produce expected results.
Key practices:
Example from message truncation logic:
// Incorrect: Can result in zero when it shouldn't
messagesToRemove = Math.floor((messages.length - startOfRest) / 8) * 3 * 2
// With messages.length=5, startOfRest=1: floor(4/8) * 3 * 2 = 0 * 6 = 0
// Correct: Properly calculates 3/4 of remaining pairs
messagesToRemove = Math.floor(((messages.length - startOfRest) * 3) / 4 / 2) * 2
// With messages.length=5, startOfRest=1: floor((4*3)/4/2) * 2 = floor(1.5) * 2 = 2
For recursive operations, implement safeguards:
// Prevent infinite recursion with cycle detection
const visitedPaths = new Set<string>()
if (visitedPaths.has(resolvedPath)) {
continue // Skip already processed paths
}
visitedPaths.add(resolvedPath)
Always use defensive programming patterns when accessing object attributes, especially when dealing with optional or potentially None values. Use hasattr() checks before accessing attributes, prefer public accessor methods over private attributes, and add null checks when accessing nested properties.
Key patterns to follow:
Example of unsafe vs safe access:
# Unsafe - direct private attribute access
if hasattr(page.context, '_browser_context_config'):
if hasattr(page.context._browser_context_config, 'anti_fingerprint'):
self.anti_fingerprint = page.context._browser_context_config.anti_fingerprint
# Safe - public accessor with null checks
if hasattr(page, 'context') and hasattr(page.context, 'get_config'):
config = page.context.get_config()
if config is not None and hasattr(config, 'anti_fingerprint'):
self.anti_fingerprint = config.anti_fingerprint
This approach prevents AttributeError exceptions, respects encapsulation, reduces coupling, and makes code more robust against null references and missing attributes.
Maintain clean and properly structured package.json files by following these principles:
Categorize dependencies correctly - place development tools and testing libraries in devDependencies, not in regular dependencies. This ensures smaller production builds and clearer dependency management.
Avoid creating custom npm scripts that merely duplicate functionality already available through standard CLI commands.
Example of proper dependency categorization:
{
"dependencies": {
"react": "^18.2.0",
"openai": "^4.89.0",
- "js-yaml": "^4.1.0",
},
"devDependencies": {
+ "js-yaml": "^4.1.0",
"typescript": "^5.0.0",
"jest": "^29.0.0"
},
"scripts": {
"build": "tsc",
- "husky:add": "husky add"
}
}
This approach keeps configuration files clean, minimizes production build size, and leverages standard tools as intended.
Always validate and sanitize untrusted inputs to prevent injection attacks and security vulnerabilities. This includes path inputs that could lead to directory traversal attacks and content that may contain malicious HTML entities.
For path validation, avoid resolving symbolic links directly as this can enable directory traversal attacks. Instead, use safe path manipulation methods that don’t follow symlinks.
For content validation, implement reusable functions to check for dangerous patterns rather than repeating validation logic:
function areUnallowedHtmlEntities(content) {
const entityNamesToBeBypassed = ['gt','lt','quot','amp','apos']
const unallowedEntityNamesRegExp = entityNamesToBeBypassed.map(entityName => `(${entityName})`).join('|')
const reg = new RegExp(`&${unallowedEntityNamesRegExp};`,'g')
return content.match(reg)?.length > 0
}
// Usage
if(areUnallowedHtmlEntities(content)) {
// Handle unsafe content
}
This approach prevents XSS vulnerabilities while maintaining clean, reusable code. Always assume inputs are malicious and validate accordingly.
Always use child_process.spawn() with array arguments instead of exec() with string concatenation when executing system commands. This prevents command injection vulnerabilities that can occur when untrusted input is incorporated into command strings.
Problematic code:
const safePreview = preview.replace(/"/g, '\\"');
const title = "Codex CLI";
exec(`osascript -e "display notification \\"${safePreview}\\" with title \\"${title}\\""`, { cwd });
Secure code:
const title = "Codex CLI";
spawn('osascript', [
'-e',
`display notification "${preview}" with title "${title}"`
], { cwd });
By passing arguments as separate array elements, the operating system receives them without interpreting special characters as command syntax, ensuring untrusted input cannot escape its intended context.
Tests should validate actual system behavior rather than just verifying method calls. When writing tests, focus on asserting the expected outcomes and side effects rather than simply checking if methods were invoked.
Bad example:
def test_task_execution():
with patch.object(Agent, "_execute", return_value="ok") as execute:
result = task.execute()
assert result.raw == "ok"
execute.assert_called_once() # Only validates the call
Good example:
@tool("test_tool", result_as_answer=True)
def delayed_tool():
sleep(5) # Actual behavior
return "ok"
def test_task_execution():
agent = Agent(tools=[delayed_tool])
task = Task(description="test", agent=agent)
result = task.execute()
assert result.raw == "ok"
# Test validates actual timing behavior
assert task.execution_time >= 5
Key points:
Always properly manage database connections to prevent resource leaks and improve application stability. Implement these key practices:
Example:
// Connection pool setup with proper configuration
const dbPool = mysql.createPool({
...dbConfig,
connectionLimit: 10,
queueLimit: 0,
connectTimeout: 10000,
});
// Function using a connection with proper release
async function queryDatabase() {
const connection = await dbPool.getConnection();
try {
const [results] = await connection.execute('SELECT id, name FROM users WHERE status = ?', ['active']);
return results;
} catch (error) {
console.error('Database query failed:', error);
throw error;
} finally {
// Always release the connection back to the pool
connection.release();
}
}
// Graceful shutdown handler
process.on('SIGTERM', async () => {
console.log('Closing database connections...');
if (dbPool) {
await dbPool.end();
console.log('Database pool closed');
}
process.exit(0);
});
Always use None as the default value for optional parameters and class attributes instead of empty collections ([], {}, "") or other mutable defaults. This prevents sharing mutable state between instances and makes null checks more explicit.
Example:
# ❌ Bad - Using mutable defaults
class ToolAdapter:
original_tools: List[BaseTool] = [] # Shared between instances
def __init__(self, items: List[str] = []): # Mutable default
self.items = items
# ✅ Good - Using None as default
class ToolAdapter:
def __init__(self):
self.original_tools: List[BaseTool] = [] # Instance-specific
def process(self, items: Optional[List[str]] = None):
items = items or [] # Convert None to empty list
# Process items...
This approach:
Use CSS utility functions and avoid complex inline calculations for better maintainability and readability. Prefer cx() from useStyles for combining CSS classes instead of template literals, and use css from antd-style for simple styles without design tokens.
Recommended patterns:
// ✅ Good: Use cx() for combining classes
const { styles, cx } = useStyles();
<div className={cx(styles.promptBox, styles.animatedContainer)} />
// ❌ Avoid: Template literal concatenation
<div className={`${styles.promptBox} ${styles.animatedContainer}`} />
// ✅ Good: Simple CSS without tokens
import { css, cx } from 'antd-style';
const extraTitle = css`
font-weight: 300;
white-space: nowrap;
`;
<div className={cx(extraTitle)} style={{ fontSize: extraSize }} />
// ❌ Avoid: Complex CSS calculations that are fragile
style={{ maxHeight: `calc(75vh - 56px - 13px - ${gap}px)` }}
Avoid overly complex CSS calculations that depend on magic numbers, as they become fragile when layouts change. Consider using CSS inheritance properties or more robust layout solutions instead.
Maintain consistent formatting when initializing AI models and agents. Use proper spacing around assignment operators and consistent indentation for constructor parameters to improve code readability and follow Python style conventions.
Key formatting rules:
Example of proper formatting:
# Good: proper spacing and indentation
llm = ChatOpenAI(base_url='https://api.novita.ai/v3/openai', model='deepseek/deepseek-v3-0324', api_key=SecretStr(api_key))
agent = Agent(
task="Your task here",
llm=llm,
planner_llm=planner_llm,
extend_planner_system_message=extend_planner_system_message
)
This ensures AI model initialization code is clean, readable, and follows established Python formatting standards.
When handling exceptions, always preserve the original error context to aid in debugging and error diagnosis. This involves two key practices: (1) Include the exception class name when converting exceptions to strings, and (2) Use exception chaining when re-raising exceptions.
For error message formatting, avoid bare str(e) or f'{e}' as these only show the error message without the exception type. Instead, use f'{type(e).__name__}: {e}' to include both the exception class and message.
When re-raising exceptions or wrapping them in custom exceptions, always preserve the original traceback using from e to maintain the full error context for debugging.
Example of proper exception context preservation:
try:
response: dict[str, Any] = await structured_llm.ainvoke(input_messages)
parsed: AgentOutput | None = response['parsed']
except Exception as e:
logger.error(f'Failed to invoke model: {type(e).__name__}: {e}')
raise LLMException(401, 'LLM API call failed') from e
# For error reporting in return values:
except Exception as e:
return {
'task_id': task_folder.name,
'judgement': None,
'success': False,
'error': f'{type(e).__name__}: {e}',
'score': 0.0
}
This practice significantly improves error diagnosis by providing complete context about what went wrong and where the error originated, making debugging much more efficient.
Commented-out code should be removed immediately rather than committed to the codebase. Keeping commented code creates confusion, adds unnecessary noise, and makes the codebase harder to maintain. If code is no longer needed, delete it - version control systems will preserve the history if it needs to be referenced later.
Example of what to avoid:
export function useDocumentTitle() {
// const settingsStore = useSettingsStore();
// const { releaseChannel } = settingsStore.settings;
// const suffix = !releaseChannel || releaseChannel === 'stable'
// ? 'n8n'
// : `n8n[${releaseChannel.toUpperCase()}]`;
}
Instead, either:
This keeps the codebase clean, current, and easier to understand for all developers.
Use appropriate version bumps to signal migration requirements and maintain clear upgrade paths. Flag breaking changes with major version bumps to help with release notes and upgrade guides. External contributors should use patch bumps only, while minor and major version changes are reserved for the core team.
Example:
# For breaking changes (core team only)
pnpm changeset
# Select 'major' for the bump type when removing APIs or making breaking changes
# For external contributors
pnpm changeset
# Select 'patch' for all contribution changes
This versioning strategy ensures users have clear signals about migration requirements and proper documentation is maintained for version transitions.
Avoid including optional or provider-specific dependencies in the main dependency list. Dependencies should only be required if they are essential for core functionality that all users need.
Make dependencies optional when they are:
Use the optional = true flag and organize them into appropriate extras groups:
[tool.poetry.dependencies]
# Core dependencies only
python = ">=3.9,<3.12"
pydantic = "^2.0"
# Optional dependencies
groq = { version = "^0.4.2", optional = true }
mistralai = { version = "^0.1.3", optional = true }
[tool.poetry.extras]
groq = ["groq"]
mistral = ["mistralai"]
This approach prevents forcing unnecessary installations on users who don’t need specific providers or features, while still making them available for those who do.
When working with AI model interfaces and result objects, ensure consistent property naming across related components. The AI ecosystem involves multiple providers and model types, making naming consistency crucial for maintainable code.
For example, use the same property name consistently when accessing similar data from model results:
// INCORRECT
console.log('Responses:', result.responses);
// CORRECT
console.log('Response:', result.response);
This consistency should extend across different AI capabilities (text generation, transcription, embedding, etc.) to create a cohesive developer experience. Inconsistent naming patterns lead to:
When designing AI interfaces or extending existing ones, audit the naming patterns of related components and align new additions with established conventions. This is particularly important when working with response objects from different AI providers that may use varying terminology for similar concepts.
When logging object properties, always verify that the property names exactly match the actual structure of the object being logged. Incorrect property names (like ‘responses’ instead of ‘response’) or non-existent properties will result in undefined values in logs, reducing their usefulness for debugging and troubleshooting.
Example of problematic code:
console.log('Responses:', result.responses); // Incorrect property name
console.log('Provider Metadata:', result.providerMetadata); // Non-existent property
Corrected code:
console.log('Response:', result.response); // Correct property name
// Don't log properties that don't exist in the object
Consider using optional chaining (?.) for nested properties or TypeScript to help catch these issues at compile time. For important logging in production code, consider adding runtime property existence checks before logging.
Configuration options should be organized based on their nature and scope of use. Place model-specific configurations in constructor parameters or config objects rather than in general settings objects that might be shared across models. Additionally, standardized settings should be consistent across providers and not duplicated in provider-specific options.
This organization improves code maintainability and prevents confusion about where settings should be defined or accessed.
// GOOD: Model-specific config in constructor parameters
constructor(
modelId: OpenAICompatibleChatModelId,
settings: OpenAICompatibleChatSettings,
config: OpenAICompatibleChatConfig & {
defaultObjectGenerationMode?: 'json' | 'tool' | undefined;
}
) { ... }
// BAD: Model-specific config in settings
export interface OpenAICompatibleChatSettings {
user?: string;
defaultObjectGenerationMode?: 'json' | 'tool' | undefined; // Should be in config instead
}
// GOOD: Standardized settings not duplicated in provider options
// For settings like 'voice' that are standardized across providers
speech.generate("Hello world", {
voice: "alloy", // Top-level standardized setting
});
// BAD: Duplicating standardized settings in provider options
speech.generate("Hello world", {
providerOptions: {
openai: {
voice: "alloy", // Duplicated standardized setting
}
}
});
For common settings that apply across different providers (like ‘voice’ for speech models or ‘language’ for transcription), define them as top-level options rather than duplicating them in each provider’s specific options.
When documenting AI systems, models, or assistants, ensure technical terminology is precise and capabilities are clearly scoped. Use consistent language to describe what the AI can and cannot do, avoiding vague or overstated claims. For AI agents or assistants, explicitly detail their tools, permissions, and limitations.
For example, instead of vague descriptions like “AI helper that can code,” use specific language:
# Clear AI Capability Documentation
Powered by Claude 3.7 Sonnet's agentic coding capabilities, this AI assistant can:
- Create and edit files with linter/compiler error monitoring
- Execute terminal commands (with user authorization)
- Browse projects and analyze code structure via AST parsing
- Use headless browser for web development tasks
Limitations: Requires human approval for each file change and terminal command.
This approach helps users understand exactly what to expect from AI tools and prevents misaligned expectations. When localizing AI documentation, maintain technical accuracy while adapting language for cultural context. Consistent terminology across all documentation languages ensures users have the same understanding regardless of their preferred language.
Always implement appropriate error handling to prevent crashes while providing clear feedback to users. Consider these principles:
Decide on error propagation strategy: Determine whether errors should be handled locally or propagated to a higher-level handler based on severity and recoverability.
Catch specific exceptions: Target exact exception types rather than using broad catches.
Use consistent error reporting: Utilize standardized error reporting mechanisms instead of print statements.
Consider platform-specific issues: Anticipate and handle platform-dependent error scenarios.
Example of proper error handling with clear propagation strategy:
def register_models(model_def_fnames):
for model_def_fname in model_def_fnames:
if not os.path.exists(model_def_fname):
continue
try:
with open(model_def_fname, "r") as model_def_file:
model_def = json.load(model_def_file)
except json.JSONDecodeError as e:
# Propagate critical configuration errors to main for centralized handling
raise ConfigurationError(f"Invalid model definition in {model_def_fname}: {e}")
except IOError as e:
# Log but continue if a file can't be read
io.tool_error(f"Could not read model definition: {e}")
When handling cleanup operations, catch specific exceptions that might occur:
try:
# Cleanup operation
shutil.rmtree(self.tempdir)
except (OSError, PermissionError):
pass # Ignore cleanup errors (especially on Windows)
For functions that might fail, clearly document return behavior and ensure consistent error state handling:
# Return values on error should be documented and consistent
try:
self.repo.git.commit(cmd)
return commit_hash, commit_message
except GitError as err:
self.io.tool_error(f"Unable to commit: {err}")
# Explicitly return None to make the error path obvious
return None
Configure separate TypeScript type-checking strategies for CI environments and local development. CI pipelines should run complete type checks that validate the entire codebase, while local development can use faster configurations to improve developer productivity.
Example implementation:
// package.json
{
"scripts": {
"type-check": "tsc --build", // Faster checks for local development
"type-check:full": "tsc --build tsconfig.with-examples.json", // Comprehensive checks for CI
"clean": "rimraf dist" // Add cleanup before builds
}
}
In your CI pipeline configuration, always use the more thorough type checking:
# CI configuration
steps:
- name: Type Check
run: npm run type-check:full
This approach ensures your CI pipeline catches all type errors while developers can work efficiently with faster feedback loops during local development. When changing build configurations, document the implications for the team and update CI pipelines accordingly.
Dependencies from packages outside your organization’s trusted domain pose security risks and should be avoided in pull requests. When package-lock.json files include external dependencies, they introduce potential vulnerabilities that bypass internal security controls.
Only include dependencies from your organization’s approved domains (e.g., internal packages, trusted vendors like AWS in this case). If external dependencies are necessary, they should be reviewed and added through internal security processes rather than directly in pull requests.
When submitting PRs:
This approach ensures all external dependencies undergo proper security vetting before being introduced to the codebase.
When handling untrusted model/text output that will be serialized into JSON (or rendered in a UI), normalize it before output generation—specifically strip or escape tag-like content (e.g., “
Apply this by adding a single sanitization/normalization step right before JSON serialization (or right before writing responses to clients):
function sanitizeTagsByLine(text) {
return text
.split(/\r?\n/)
.map(line => line
// remove thinking tags that can break JSON/UI parsing
.replace(/<\s*think\s*>[\s\S]*?<\s*\/\s*think\s*>/gi, "")
// optionally remove any stray <think> tags
.replace(/<\s*think\s*>/gi, "")
.replace(/<\s*\/\s*think\s*>/gi, "")
)
.join("\n");
}
const raw = modelOutputText; // untrusted
const safe = sanitizeTagsByLine(raw);
const json = JSON.stringify({ content: safe });
Also add a quick sanity check (e.g., ensure the produced payload is valid JSON and the UI receives expected fields) so tag-related issues are caught early.
Treat any tag/markup coming from user input, LLM output, or external commands as untrusted. Validate and sanitize it at the earliest boundary before embedding into JSON or rendering in the UI—e.g., strip/escape disallowed tags so they can’t break parsers or visuals.
Example (shell boundary sanitization):
# sanitize_tags.sh
# Remove/neutralize disallowed tags before downstream UI/JSON handling
sanitize_tags() {
# Example: drop <thinking>...</thinking>
sed -E 's#<\/?thinking[^>]*>##g'
}
INPUT="$1"
SAFE_INPUT="$(printf '%s' "$INPUT" | sanitize_tags)"
# Use $SAFE_INPUT for any JSON generation or UI rendering
Apply this by: (1) defining allowed vs. disallowed tags, (2) sanitizing/escaping before JSON construction and before UI templating/rendering, and (3) adding automated tests for payloads that previously broke visuals/JSON (e.g., special tags).
Error messages should include specific context about what went wrong and provide actionable guidance for resolution. Avoid generic error messages that leave developers guessing about the root cause or solution.
When throwing errors:
Example of improved error messaging:
// Poor: Generic error message
throw new Error("act() is not implemented on the base page object");
// Better: Contextual error with actionable guidance
throw new Error(
"act() is not implemented on the base page object. Ensure you are calling init() on the Stagehand object before calling methods on the page object."
);
// Best: Include original error details when wrapping
constructor(error?: unknown) {
if (error instanceof Error || error instanceof StagehandError) {
super(
`\nHey! We're sorry you ran into an error. \nIf you need help, please open a Github issue or reach out to us on Slack: https://stagehand.dev/slack\n\nFull error:\n${error.message}`
);
}
}
This approach reduces debugging time and improves the developer experience by making failures self-explanatory.
When handling asynchronous operations, especially those that might continue running in the background after the main consumer has moved on, provide error callback options to ensure errors are properly reported and handled. This pattern prevents silent failures in background tasks and enables proper logging, monitoring, and recovery.
For example, when consuming streams:
// Without error handling - errors might be silently lost
result.consumeStream(); // no await
// With error handling - errors are properly reported
result.consumeStream(error => {
console.log('Error during background stream consumption: ', error);
// Optional: report to monitoring system
});
This approach is particularly important for background operations like stream consumption where the operation continues even when the client response is aborted (e.g., when a browser tab is closed). By implementing error callbacks, you ensure that errors are visible and actionable rather than silently failing.
When implementing communication between multiple threads, ensure that messages are correctly routed to their intended recipients. Avoid designs where all worker threads consume from a single shared queue when messages are intended for specific threads, as this creates race conditions where messages can be processed by the wrong thread.
Instead, consider one of these approaches:
Example of problematic code:
def _server_loop(self, server: McpServer, loop: asyncio.AbstractEventLoop) -> None:
while True:
# All threads compete for the same messages
msg: CallArguments = self.message_queue.get()
# If message not for this server, discard it
if msg.server_name != server.name:
self.message_queue.task_done()
continue
# Process the message...
Better implementation:
class McpManager:
def __init__(self):
# One queue per server for proper message routing
self.server_queues = {} # server_name -> queue
self.result_queue = queue.Queue()
def add_server(self, server_name):
self.server_queues[server_name] = queue.Queue()
def _call(self, io, server_name, function, args={}):
# Route message to specific server queue
if server_name in self.server_queues:
self.server_queues[server_name].put(CallArguments(server_name, function, args))
result = self.result_queue.get()
return result.response
return None
def _server_loop(self, server: McpServer, loop: asyncio.AbstractEventLoop) -> None:
# Each server only processes its own messages
server_queue = self.server_queues[server.name]
while True:
msg = server_queue.get()
# Process message...
This pattern prevents race conditions and ensures messages are always processed by their intended recipients.
When merging configuration objects, always preserve existing values and follow clear precedence rules to avoid unintentionally overriding settings. Use spread operators carefully and ensure the merge logic is implemented at the appropriate layer (preferably in action/store layer rather than component level).
Key principles:
{} that can override existing configurationsExamples:
❌ Problematic merging - overwrites existing footerAction:
appearance={{
...appearance,
elements: {
...appearance.elements,
footerAction: !enableClerkSignUp ? { display: 'none' } : {}, // Empty object overwrites existing
}
}}
✅ Proper conditional merging:
appearance={{
...appearance,
elements: {
...appearance.elements,
...((!enableClerkSignUp) && { footerAction: { display: 'none' } }),
}
}}
❌ Component-level merging:
onChange={(value) => {
updatePluginSettings(id, { [item.name]: value }); // Overwrites other settings
}}
✅ Store-level merging:
// In store action
updatePluginSettings: (id, updates) => {
set((state) => ({
pluginSettings: {
...state.pluginSettings,
[id]: { ...state.pluginSettings[id], ...updates }
}
}));
}
This approach ensures configuration integrity and prevents accidental loss of user preferences or system settings.
Adopt a “type-correct, DRY, and clean” coding style.
Rules: 1) Make type hints compile and be precise
Dict, List, Union, etc., import them from typing (or use built-in dict/list where appropriate).intention: Dict[str, Union[str, List[str]]] = {}) to avoid ambiguous types.2) Remove unused assignments and dead code
3) Avoid redundant abstractions/config branches
Example (typing + unused-code cleanup):
from typing import Dict, List, Union
def parse_intent(text: str) -> Dict[str, Union[str, List[str]]]:
intention: Dict[str, Union[str, List[str]]] = {} # typed and initialized
# ... parse JSON, fill intention ...
return intention
Example (DRY via config flag):
def explore(..., graph_store):
similarity_search_enabled = graph_store.get_config().similarity_search_enabled
if similarity_search_enabled:
# do embedding/search logic
pass
# else: fall through
Enforce these checks in review and via tooling (lint/type checker) so style remains consistent and code stays maintainable.
Ensure tests are comprehensive and explicit to prevent regressions and gaps in coverage. Tests should cover all scenarios including edge cases, error conditions, and boundary conditions. Avoid vague assertions that could pass even when the implementation is incorrect.
Key practices:
Example of explicit vs vague testing:
# Vague - could pass even if no parameters are missing
assert len(missing_params) < max_allowed
# Explicit - tests exact expected behavior
assert len(missing_params) == 2
assert "required_field" in missing_params
assert "another_field" in missing_params
When adding new features or modifying behavior, always ask: “What scenarios could break this?” and “What edge cases am I not testing?” This prevents regressions and ensures robust, reliable code.
Favor clear, simple algorithmic implementations over complex custom logic. When faced with algorithmic choices, prefer built-in functions, direct approaches, and well-structured decomposition into stages.
Key principles:
Example of good decomposition (from discussion 5):
# Stage 1: Gather all results
all_results = chain.from_iterable(await asyncio.gather(*tasks))
# Stage 2: Remove duplicates
unique_results = list(set(all_results))
# Stage 3: Get top results
top_results = sorted(unique_results, key=lambda r: r.distance)[:max_terms]
Example of lookup table approach (from discussion 7):
tests = {
"equal_to": lambda a, b: a == b,
"not_equal_to": lambda a, b: a != b,
"regex": lambda a, b: re.match(str(a), str(b)),
}
for test, value in conditions.items():
if not tests[test](value, candidate.get(field)):
return False
This approach improves code maintainability, reduces bugs, and makes algorithmic intent clearer to other developers.
When designing API clients, encapsulate responses in typed objects rather than passing raw JSON throughout your codebase. This improves maintainability, enables better error handling, and provides type safety.
For HTTP API clients, use session objects to handle common configurations like authentication headers and base URLs. This approach reduces code duplication and creates a cleaner interface.
Example:
# Instead of this:
def _make_request(self, method: str, endpoint: str, **kwargs) -> requests.Response:
url = f"{self.base_url}/{endpoint}"
return requests.request(method, url, headers=self.headers, **kwargs)
# Do this:
class CrewAPI:
def __init__(self, api_key: str) -> None:
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
})
self.base_url = "https://api.example.com/v2"
def deploy_by_name(self, project_name: str) -> DeployResponse:
"""Deploy a project by name and return a typed response."""
url = f"{self.base_url}/deploy/{project_name}"
response = self.session.post(url)
if not response.ok:
raise APIError(response.json())
return DeployResponse.from_json(response.json())
class DeployResponse:
"""Typed representation of a deployment response."""
uuid: str
status: str
timestamp: datetime
@classmethod
def from_json(cls, data: dict) -> 'DeployResponse':
# Convert raw JSON to typed object
return cls(**data)
This pattern ensures that API-specific concerns stay in the client implementation while providing a clean, type-safe interface for consumers.
Replace native shell commands in package.json scripts with cross-platform alternatives to ensure build consistency across different operating systems. Native commands like rm -rf fail on Windows, breaking CI/CD pipelines that run on mixed environments.
Use tools like shx or rimraf instead of native shell commands:
{
"scripts": {
// ❌ Not cross-platform compatible
"clean": "rm -rf build",
"build": "rm -rf dist && rslib build && chmod +x dist/*.js",
// ✅ Cross-platform compatible
"clean": "shx rm -rf build",
"build": "shx rm -rf dist && rslib build && shx chmod +x dist/*.js"
}
}
This ensures your build scripts work reliably in CI/CD environments regardless of the underlying operating system, preventing deployment failures due to platform-specific command incompatibilities.
Always consider and respect browser native behaviors when implementing web application features. Avoid conflicts with built-in browser shortcuts and choose appropriate client vs server-side approaches based on the execution environment.
Key considerations:
Example from hotkey implementation:
// Avoid: Using 'mod' which maps to 'cmd' on Mac, conflicting with browser tabs
useHotkeys(list.slice(0, 9).map((e, i) => `mod+${i + 1}`), handler);
// Prefer: Use 'ctrl' explicitly to avoid browser shortcut conflicts
useHotkeys(list.slice(0, 9).map((e, i) => `ctrl+${i + 1}`), handler);
Example from navigation:
// Avoid: Server redirect that fails in production
return redirect(urlJoin('/settings', searchParams.tab));
// Prefer: Client-side redirect for better compatibility
// Use client-side navigation instead
This ensures better user experience by respecting established browser conventions and avoiding runtime errors in production environments.
When writing security-sensitive shell scripts, use strict error handling to fail immediately on errors rather than attempting fallbacks or continuing silently. Always include set -euo pipefail to exit on errors, treat unbound variables as errors, and propagate pipeline failures. This prevents partial application of security configurations that could leave systems in a vulnerable state.
#!/bin/bash
# Always use strict error handling in security scripts
set -euo pipefail # Exit on error, undefined vars, and pipeline failures
IFS=$'\n\t' # Stricter word splitting
# Critical security operations
iptables -F
ipset create allowed-domains hash:net
# External dependencies should fail explicitly rather than silently continuing
gh_ranges=$(curl -s https://api.github.com/meta)
if [ -z "$gh_ranges" ]; then
echo "ERROR: Failed to fetch GitHub IP ranges"
exit 1
fi
By failing fast on errors, you ensure that security configurations are either completely applied or not applied at all, avoiding inconsistent states that could create security vulnerabilities. For security-critical code, avoid fallback mechanisms like the try_cmd pattern that might silently continue after failures.
SVG files can execute code when loaded, making them a potential security vulnerability. Before using SVGs, evaluate the deployment context and security requirements. Different environments have different restrictions - for example, VS Code marketplace prohibits user-provided SVGs due to security concerns, while webview-hosted SVGs may be acceptable. When SVGs pose security risks, consider safer alternatives like base64-encoded images or icon pack fonts. Be especially cautious with user-provided SVG content that could be modified to contain malicious code.
Example of context-aware SVG handling:
// Risky: User-provided SVG for marketplace
const userSvg = getUserProvidedSvg(); // Could contain malicious code
// Safer alternatives:
const base64Image = convertToBase64(imageFile);
const iconFont = registerIconPackFont();
const controlledSvg = getStaticSvgFromAssets(); // Known safe content
When external APIs or dependencies provide cryptic or unhelpful error messages, wrap them with user-friendly, actionable guidance. This is especially important when the external service returns terse responses that don’t help users understand what went wrong or how to fix it.
Transform generic errors into specific, step-by-step instructions that guide users toward resolution. Include relevant links, configuration steps, or troubleshooting information.
Example:
// Instead of letting cryptic API errors bubble up
if (!this.options.fireworksApiKey) {
yield {
type: "text",
text: "ERROR: Fireworks API key is required but was not provided.\n\n" +
"Please set your API key in the extension settings:\n" +
"1. Open the KiloCode settings panel\n" +
"2. Select 'Fireworks' as your provider\n" +
"3. Enter your API key\n\n" +
"You can get your API key from: https://fireworks.ai/account/api-keys",
}
return
}
This approach is justified when external services provide inadequate error context (like Fireworks returning just {"error":"unauthorized"} instead of OpenAI’s detailed error messages). The enhanced messages should be implemented at the API boundary to avoid duplicating error handling logic throughout the codebase.
Restrict network access to only what’s necessary for your application to function, using explicit allowlisting rather than trying to block malicious traffic. Network traffic should be denied by default and only specifically required destinations should be allowed.
When implementing network restrictions:
For example, when configuring container firewalls:
# Create default deny policy
iptables -P OUTPUT DROP
# Create allowlist for domains
ipset create allowed-domains hash:net
# Add only necessary domains
for domain in "api.required-service.com" "cdn.dependencies.org"; do
ips=$(dig +short A "$domain")
for ip in $ips; do
ipset add allowed-domains "$ip"
done
done
# Allow only traffic to allowlisted destinations
iptables -A OUTPUT -m set --match-set allowed-domains dst -j ACCEPT
# Test the configuration works as expected
if curl --connect-timeout 5 https://blocked-domain.com >/dev/null 2>&1; then
echo "ERROR: Firewall verification failed"
fi
Remember that network restrictions should be combined with other security controls (defense in depth). As shown in the discussion about S3 access, network allowlisting can be paired with credential restrictions to provide multiple layers of security.
When documenting configuration settings, environment setup, or system requirements, explicitly state assumptions about the target environment and provide accurate default values. Avoid making implicit assumptions that may not apply to all users or deployment scenarios.
For configuration settings, ensure documented default values match the actual implementation:
- `cline.editor.skipDiffAnimation`: Disable the animated diff view when Cline makes changes to files. This can significantly speed up file modifications, especially when working with remote repositories. Default: `false`
For environment-specific instructions, acknowledge the target system and note alternatives:
**Linux-specific Setup (Debian/Ubuntu)**
If you're developing on Debian-based Linux distributions, you'll need to install additional system libraries:
```bash
sudo apt update
sudo apt install -y libatk1.0-0 libatk-bridge2.0-0 ...
Note: For RHEL, Arch, or Alpine systems, equivalent packages will have different names and installation methods.
This practice prevents confusion, reduces support burden, and ensures users can adapt instructions to their specific environments.
---
## synchronize configuration environments
<!-- source: stanfordnlp/dspy | topic: Configurations | language: Yaml | updated: 2025-03-03 -->
Ensure configuration values remain consistent between local development and CI/CD environments, and document the rationale behind environment-specific settings. Version mismatches and undocumented configuration behavior can lead to unexpected failures and developer confusion.
When updating configuration values like dependency versions, tool versions, or environment variables, verify they match across all environments. Add explanatory comments for configurations that have non-obvious behavior or requirements.
Example:
```yaml
env:
# Keep in sync with poetry.lock - developers use 1.7.1 locally
POETRY_VERSION: "1.7.1"
- name: Create test environment
# Virtual env activation changes sys.path, excluding working dir
# Installation is required for imports to work properly
run: python -m venv test_env
Regularly audit configuration files to catch drift between local development tools and CI/CD pipeline settings.
Documentation should provide clear contextual information that helps users understand when they need to take specific actions versus when configurations are automatically handled. Include deployment-specific details and maintain consistent cross-referencing syntax throughout.
When documenting configuration options, specify the conditions under which manual setup is required:
| Environment Variable | Type | Description |
| -------------------- | ---- | ----------- |
| `NEXT_PUBLIC_ENABLE_NEXT_AUTH` | Required | Used to enable NextAuth service. Set to `1` to enable; changing this setting requires recompiling the application. Users deploying with the `lobehub/lobe-chat-database` image have this configuration added by default. |
For cross-references, use consistent linking syntax that matches the existing documentation structure:
This configuration is done in the environment for each [model providers](/docs/self-hosting/environment-variables/model-provider).
This approach reduces user confusion by clearly indicating when manual intervention is needed and ensures documentation maintains professional consistency.
Always recommend user-level package installations rather than using administrative/root privileges. Installing packages with elevated permissions can compromise system security and stability. Documentation and scripts should explicitly guide users toward safer installation practices.
Example:
# Installation
## User-level installation (recommended)
```sh
mkdir -p ~/.local/share/npm-packages
npm config set prefix ~/.local/share/npm-packages
export PATH=~/.local/share/npm-packages/bin:$PATH
npm install -g my-package
We recommend installing this package as a regular user, not as an administrative user like root. Installing as a regular user helps maintain your system’s security and stability.
---
## Environment-specific configuration handling
<!-- source: lobehub/lobe-chat | topic: Configurations | language: Shell | updated: 2025-02-26 -->
When writing configuration scripts, ensure they handle environment-specific differences properly by using predefined path variables and adapting commands for different operating systems. Use consistent variable naming for paths that may vary between environments, and implement OS detection when commands have different syntax across platforms.
For path management, always use predefined variables when referencing configuration files:
```bash
SUB_DIR="docker-compose/local"
FILES=(
"$SUB_DIR/docker-compose.yml"
"$SUB_DIR/init_data.json"
"$SUB_DIR/searxng-settings.yml"
)
For cross-platform compatibility, detect the operating system and adapt commands accordingly:
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
SED_COMMAND="sed -i ''"
else
SED_COMMAND="sed -i"
fi
This approach ensures configuration scripts work reliably across different environments while maintaining consistency in path handling and command execution.
Follow auth.js standardized environment variable naming conventions and use explicit function declarations for OAuth providers. Use the AUTH_[PROVIDER_ID]_ID format for environment variables as auth.js automatically reads these. Avoid deprecated naming patterns that will be removed in future versions. Explicitly declare scope and profile handling functions rather than relying on defaults.
Example:
// Use standardized environment variables (auto-read by auth.js)
// AUTH_FEISHU_ID=your_app_id
// AUTH_FEISHU_SECRET=your_secret
function Feishu(): OAuthConfig<FeishuProfileResponse> {
return {
authorization: {
params: {
scope: '', // Explicitly declare scope
},
url: 'https://accounts.feishu.cn/open-apis/authen/v1/authorize',
},
// Explicitly declare profile function
profile(profileResponse) {
const profile = profileResponse.data;
return {
id: profile.union_id,
image: profile.avatar_url,
name: profile.name,
providerAccountId: profile.union_id,
};
},
// ... other config
};
}
For client-side auth components, prefer dynamic imports to optimize bundle size:
const { signOut } = await import("next-auth/react");
Design API methods with structured object parameters instead of ordered parameters or loose typing. Use proper TypeScript types rather than any, and consider parameter patterns that enhance safety and flexibility.
Key principles:
function(param1, param2, param3), use function({ param1, param2, param3 }) for better readability and extensibilityany types with specific interfaces like GotoOptions to provide better developer experience and catch errors earlycontext.pages()[index] instead of direct page references{ action: "search for %query%", variables: { query: "value" } }Example transformation:
// Before: Ordered parameters with loose typing
page.goto = async (url: string, options?: any) => { ... }
// After: Proper typing and structured approach
page.goto = async (url: string, options?: GotoOptions) => { ... }
// Before: Multiple ordered parameters
resolveLLMClient(llmClient, modelName, requestId)
// After: Object parameter with proper typing
resolveLLMClient({
llmProvider,
modelName,
requestId
}: {
llmClient?: LLMClient,
modelName?: AvailableModel,
requestId?: string
})
This approach improves API discoverability, reduces parameter ordering mistakes, and makes future extensions easier without breaking existing code.
When annotating optional or nullable types in Python, ensure compatibility across all supported Python versions. For codebases supporting Python 3.9:
from __future__ import annotations at the top of files using the union type syntax:
from __future__ import annotations
class ExInfo:
name: str
retry: bool
description: str | None
typing.Optional[X] instead of X | None syntax:
import typing
class CoderPrompts:
repo_content_prefix: typing.Optional[str] = """Here are summaries..."""
This ensures proper null handling with type annotations while maintaining backward compatibility with Python 3.9, preventing runtime errors like TypeError: unsupported operand type(s) for |: 'type' and 'NoneType'.
Always commit dependency lock files (poetry.lock, package-lock.json, etc.) to version control and maintain their consistency across development environments. Lock files ensure reproducible builds and prevent environment mismatches that can cause unexpected changes or build failures.
Before updating lock files, ensure your local environment matches the project’s requirements by running the appropriate install command first. For Poetry projects, run poetry install before poetry lock to avoid introducing unrelated changes from environment mismatches.
Example workflow for Poetry:
# First, sync your environment with the existing lock file
poetry install
# Then update dependencies if needed
poetry lock
# Commit both pyproject.toml and poetry.lock
git add pyproject.toml poetry.lock
Never add lock files to .gitignore as they are essential for maintaining consistent dependency versions across all development and deployment environments.
Maintain consistent naming conventions within related groups of identifiers. When naming related variables, functions, or constants, use the same naming pattern and style to improve code readability and maintainability.
Apply consistent patterns for:
Example from discussions:
// Good: Consistent environment variable naming
FEISHU_APP_ID: process.env.FEISHU_APP_ID,
FEISHU_APP_SECRET: process.env.FEISHU_APP_SECRET,
// Good: Consistent database field naming
emailVerifiedAt: timestamptz('email_verified_at'),
clerkCreatedAt: timestamptz('clerk_created_at'),
// Good: Specific, descriptive function names
initAgentRuntimeWithUserPayload() // Clear object and action
// Good: Context-appropriate naming
// Config files use snake_case
embedding_model: DEFAULT_FILE_EMBEDDING_MODEL_ITEM,
// Code variables use camelCase
embeddingModel: config.embedding_model,
This consistency reduces cognitive load when reading code and makes the codebase more predictable for developers.
Always maintain complete error information when logging or re-throwing errors to enable effective debugging and monitoring. This includes using structured logging instead of console methods, chaining original errors when throwing new ones, and ensuring underlying errors are not masked by generic error handling.
When logging errors, use structured logging with the error object:
// Instead of
console.error(`There was an error searching for content: ${error.message}`);
// Use
logger.error(`There was an error searching for content`, { error });
When re-throwing errors, preserve the original error context:
// Instead of
throw new Error("Failed to convert rawHtml to UTF-8");
// Use
throw new Error("Failed to convert rawHtml to UTF-8", { cause: error });
Avoid silently continuing on failures that should be propagated - throw errors to capture the correct context rather than masking underlying issues with generic error messages or type errors.
Environment variables should be validated at startup or module initialization rather than at runtime usage. Use non-null assertion operators or explicit validation checks to fail fast when required configuration is missing, preventing delayed runtime errors and making configuration issues immediately apparent during development and deployment.
Instead of logging errors and continuing execution:
const url = process.env.SEARXNG_ENDPOINT as string;
if (!url) {
console.error(`SEARXNG_ENDPOINT environment variable is not set`);
}
// Code continues and may fail later...
Use non-null assertion for required variables:
const url = process.env.SEARXNG_ENDPOINT!;
Or implement explicit validation at module initialization:
if (!process.env.SEARXNG_ENDPOINT) {
throw new Error('SEARXNG_ENDPOINT environment variable is required');
}
This approach ensures configuration problems are caught early in the application lifecycle rather than causing mysterious runtime failures.
Design API endpoints with concise, direct naming that clearly communicates their purpose without unnecessary verbosity. Avoid redundant prefixes or overly descriptive names that make endpoints harder to remember and use. Choose built-in language features over custom implementations when possible to improve reliability and maintainability.
For endpoint naming, prefer the core functionality over implementation details:
// Avoid verbose prefixes
v1Router.post("/generate-llmstxt", ...) // ❌ Too verbose
// Prefer direct, clear naming
v1Router.post("/llmstxt", ...) // ✅ Concise and clear
For implementation, leverage built-in APIs over custom logic:
// Avoid custom regex for URL handling
const isCompleteUrl = new RegExp('^(?:[a-z+]+:)?//', 'i');
if (!isCompleteUrl.test(link)){
link = this.baseUrl + link;
}
// Use built-in URL constructor
const url = new URL(link.trim(), this.baseUrl); // ✅ Simpler and more reliable
This approach improves developer experience by making APIs more intuitive to use and implementations easier to understand and maintain.
Use TypeScript’s type system proactively to prevent null and undefined issues at compile time rather than handling them reactively at runtime. This includes using exhaustive pattern matching, explicit type annotations, and avoiding type casting that can hide null safety problems.
Key practices:
default: { throw exhaustiveMatchingGuard(action); }const result: AnthropicTransformedResponse instead of return result as Tconst xpaths = elementId === null ? ["//body"] : selectorMap[elementId] ?? [];Array<{ input: EvalInput; output?: boolean }> instead of generic arraysExample of good null safety:
// Instead of type casting that hides null issues
return cachedResponse as T;
// Use explicit typing
const cachedResponse: AnthropicTransformedResponse | undefined = this.cache.get(...);
if (cachedResponse) {
return cachedResponse;
}
This approach catches potential null/undefined issues during development rather than discovering them at runtime.
When handling exceptions, preserve the original exception context and provide clear, actionable error information. Avoid creating new exceptions that lose important details from the original error, and replace generic error handling (like assertions) with specific, user-friendly messages.
Key practices:
Example of what NOT to do:
# Loses original exception context
except RateLimitError as e:
raise RateLimitError(RATE_LIMIT_ERROR_MESSAGE, response=e.response, body=e.body)
# Generic assertion without clear message
assert condition or action
Example of better approach:
# Preserve context with logging
except RateLimitError as e:
logger.error(RATE_LIMIT_ERROR_MESSAGE)
raise # Re-raise original exception
# Clear error message
if not (condition or action):
raise ValueError("At least one of --condition or --action is required")
set_exit_status(1)
This ensures that debugging information is preserved while still providing clear feedback to users about what went wrong and how to fix it.
When adding AI/ML libraries to a project, carefully consider whether they belong in dependencies or devDependencies. Libraries used for examples, experimentation, or development tooling should be classified as devDependencies to avoid bloating production bundles. Maintain consistency by avoiding install scripts in package.json for dev-only AI libraries.
Example:
// Correct - AI libraries for examples/development
"devDependencies": {
"@langchain/core": "^0.3.40",
"@langchain/openai": "^0.4.4"
}
// Avoid install scripts for dev dependencies
"scripts": {
"example": "npm run build-dom-scripts && tsx examples/example.ts"
// Not: "langchain": "npm install @langchain/core @langchain/openai && ..."
}
This ensures production deployments only include necessary AI dependencies while keeping development and example code properly isolated.
When making configuration changes, especially those involving version specifications or constraints, include explanatory comments with links to relevant issues, PRs, or documentation. This provides context for future maintainers and makes the reasoning behind configuration decisions transparent and traceable.
For dependency versions, document why specific version constraints were chosen:
dependencies:
- together>=1.1.0 # Use >= for compatibility, see issue #236
For CI/CD matrices, explain version selection rationale:
strategy:
matrix:
python-version: ["3.11", "3.12"] # Dropped 3.10 support, see PR #123
This practice helps team members understand the historical context of configuration decisions and prevents unnecessary changes or confusion during future updates.
When CI workflows mix multiple uv steps (e.g., install built wheels, then run tests/lint), make dependency installation deterministic and prevent later steps from overwriting earlier artifact installs.
Apply these rules:
uv lock --check (or equivalent in your uv_setup).uv sync --group <name> ....uv sync is subtractive: it can remove deps not in the selected group(s) (so expect functional differences vs non-sync installs).uv run), stop uv from resynchronizing that environment.
uv sync --only-group test ...).UV_NO_SYNC=true when using uv run/test commands that would otherwise sync and replace the wheel with the local project.Example pattern (wheel install + tests without overwriting):
# Install built wheel artifacts
uv pip install dist/*.whl
# Prevent later uv operations (including under uv run) from syncing/overwriting
export UV_NO_SYNC=true
# Run tests (may internally call uv run)
make tests # should behave like: uv run --group test pytest ...
For group-scoped test deps, prefer:
uv sync --only-group test
# then run tests
uv run pytest
This avoids the common CI failure mode where a built wheel install is replaced by the local project (or where earlier dependency changes vanish after a later uv run).
Avoid precomputing expensive operations when they may not be needed, especially for large datasets. Instead, compute values on-demand when they are actually required. This prevents unnecessary work and improves performance for scenarios where only a subset of computed values will be used.
When designing algorithms, resist the temptation to use oversimplified heuristics or “quick fixes” that may create edge cases. Take time to implement proper solutions rather than relying on magic numbers or hacky workarounds.
Example of the problem:
// Bad: Precomputing XPaths for all nodes
for (const node of nodes) {
if (node.backendDOMNodeId !== undefined) {
const xpath = await getXPathByResolvedObjectId(cdpClient, objectId);
node.xpath = xpath; // May never be used
}
}
// Good: Compute XPaths only when needed
async function getXPathForNode(node: AXNode): Promise<string> {
if (!node.xpath && node.backendDOMNodeId) {
node.xpath = await getXPathByResolvedObjectId(cdpClient, node.backendDOMNodeId);
}
return node.xpath;
}
This approach scales better with large datasets and avoids wasted computation cycles on unused data.
Always parameterize values that might vary across different environments or users instead of hardcoding them in your code. This applies to API endpoints, regions, dimensions, credentials, and other configuration values.
When providing fallbacks to environment variables, use nullish coalescing (??) to only override missing values rather than replacing all values if any are missing:
// ❌ Don't do this
if (!id || !secret || !uri) {
id = getEnvironmentVariable("OUTLOOK_CLIENT_ID");
secret = getEnvironmentVariable("OUTLOOK_CLIENT_SECRET");
uri = getEnvironmentVariable("OUTLOOK_REDIRECT_URI");
}
// ✅ Do this instead
id = id ?? getEnvironmentVariable("OUTLOOK_CLIENT_ID");
secret = secret ?? getEnvironmentVariable("OUTLOOK_CLIENT_SECRET");
uri = uri ?? getEnvironmentVariable("OUTLOOK_REDIRECT_URI");
For service defaults, prefer leaving values unset when possible and let the backend/service set the defaults. This prevents issues when service providers change their best practices:
// ❌ Don't hardcode dimensions, regions, endpoints, etc.
vectorSearchDimensions: 1536, // Hardcoded to ada-002's size
// ✅ Make these configurable via parameters
vectorSearchDimensions: config.dimensions || embeddings.dimensions,
When integrating with SDKs, only pass overridden values and avoid setting unnecessary defaults:
// ❌ Don't do this
const app = new FirecrawlApp({ apiKey: this.apiKey, apiUrl: "https://api.firecrawl.dev" });
// ✅ Do this instead
const params = { apiKey: this.apiKey };
if (this.apiUrl !== undefined) {
params.apiUrl = this.apiUrl;
}
const app = new FirecrawlApp(params);
When integrating LLMs/embeddings into production code, treat the model as unreliable: enforce a stable IO contract (especially JSON), validate and safely recover from format mismatches, and route model calls through the project’s unified abstractions with configurable parameters.
Apply this checklist: 1) Make LLM outputs contract-safe
Example (defensive JSON parsing):
import json, re
from typing import Optional, Dict
def parse_llm_json(text: str) -> Dict:
# 1) Prefer ```json ... ```
code_block = re.search(r"```json\s*(.*?)\s*```", text, re.S|re.I)
candidate = code_block.group(1) if code_block else None
# 2) Fallback: first JSON object
if not candidate:
obj = re.search(r"\{.*?\}", text, re.S)
candidate = obj.group(0) if obj else ""
if not candidate:
return {}
try:
data = json.loads(candidate)
except json.JSONDecodeError:
return {}
# 3) Validate minimum contract
if not isinstance(data, dict):
return {}
return data
2) Never call provider SDKs directly in core business logic
3) Keep embeddings/models configurable and extensible
embedding_fn (or an equivalent abstraction) so switching embedding providers/models doesn’t require code changes.4) Keep message/history handling consistent
5) Add fallback behavior for empty/failed vector sub-results
This standard prevents production breakage from minor LLM formatting drift, improves portability across LLM providers, and makes embedding/model changes safe and configuration-driven.
When handling failures, avoid broad try/except that hides root causes. Catch only the exceptions you expect, log a warning (with enough context to debug), and preserve the original error/stack trace. For unsupported/unimplemented functionality or dependency/version mismatches, fail explicitly with clear, actionable error messages.
Practical rules:
except SpecificError as e: over except Exception:.finally that runs after an exception).raise NotImplementedError(...) (or add a TODO for later), rather than silently passing.Example pattern:
import json
import logging
logger = logging.getLogger(__name__)
async def try_text2gql(text, intent_interpreter, text2cypher, graph_adapter):
try:
intention = await intent_interpreter.translate(text)
interaction = await text2cypher.translate(json.dumps(intention))
query = interaction.get("query", "")
if "LIMIT" not in query:
query += " LIMIT 10"
return graph_adapter.query(query=query)
except (KeyError, ValueError) as e: # expected failures only
logger.warning("text2gql failed; falling back. text=%r err=%s", text, e)
return None
This keeps behavior predictable, makes production issues diagnosable, and ensures that truly unexpected bugs are not masked.
Write code so nullable/missing data can’t cause runtime errors.
Apply these rules: 1) Declare nullability in types
None, type it as Optional[...].2) Use safe dict/JSON access
dict.get("key") instead of dict["key"].3) Guard empty sequences before indexing
choices[0], rows[0], etc., check the sequence is non-empty (and the expected object shape exists).4) Use is not None instead of truthiness for config inclusion
if value is not None: so meaningful falsy values aren’t accidentally dropped.Example:
from typing import Optional
def parse_intent(payload: dict) -> Optional[str]:
# key may be missing -> use get
return payload.get("rewrited_question")
def handle_response(r):
# choices may be missing/empty -> guard before indexing
choices = r.get("choices") if isinstance(r, dict) else getattr(r, "choices", None)
if not choices:
return None
first = choices[0]
return getattr(first.delta, "content", None)
def build_config(cfg_obj):
config_dict = {}
for key in cfg_obj.model_dump().keys():
value = getattr(cfg_obj, key)
if value is not None: # not: if value:
config_dict[key] = value
return config_dict
Outcome: fewer KeyError, IndexError, and silent config-misbehavior, while making null/empty cases explicit and testable.
Always throw specific, actionable errors instead of returning unexpected values or simply logging issues. Error messages should be clear, concise, and contain the exact reason for failure without redundancy.
Consider these practices:
// Good _combineLLMOutput(): Record<string, any> | undefined { throw new Error(“AzureMLChatOnlineEndpoint._combineLLMOutput called, but is not implemented.”); }
2. Avoid redundant error prefixes that will be repeated in logs:
```typescript
// Bad - creates redundant messages
if (!response.ok) {
throw new Error(`Error authenticating with Reddit: ${response.statusText}`);
}
// Good - concise and clear
if (!response.ok) {
throw new Error(response.statusText);
}
// Good - allows callers to handle the error try { await this.collection.deleteMany({}); } catch (error) { console.error(“Error clearing sessions:”, error); throw error; // Re-throw or throw a more specific error }
4. Preserve error structures expected by error handling mechanisms:
```typescript
// Bad - overwrites properties needed for retry logic
(error as any).details = { /* ... */ };
// Good - maintains expected structure
(error as any).response = res;
Well-designed error handling improves debugging efficiency and creates a more robust application.
When launching threads in DSPy, ensure that child threads inherit the parent thread’s local overrides to maintain consistent behavior across concurrent executions. DSPy uses thread-local settings that must be properly propagated to avoid subtle runtime issues.
Critical Implementation Pattern:
from dspy.dsp.utils.settings import thread_local_overrides
def _wrap_function(self, function):
def wrapped(item):
# Capture parent thread's overrides
original_overrides = thread_local_overrides.overrides
# Create isolated copy for this thread
thread_local_overrides.overrides = thread_local_overrides.overrides.copy()
try:
return function(item)
finally:
# Restore original state
thread_local_overrides.overrides = original_overrides
return wrapped
# When launching threads, pass parent overrides:
parent_overrides = thread_local_overrides.overrides.copy()
executor.submit(cancellable_function, parent_overrides, item)
Why This Matters:
When to Apply:
ThreadPoolExecutor or similar threading mechanismsThis pattern ensures that DSPy’s internal state management works correctly across all concurrent operations, preventing hard-to-debug issues that only manifest under specific threading conditions.
When documenting AI integrations, provide comprehensive examples that showcase all common initialization and usage patterns. Documentation should include:
.fromDocuments, etc.)For example, when documenting a vector store integration:
// Show direct initialization
const vectorStore = new AIVectorStore(new SomeEmbeddings());
// Also show initialization from documents
const documents = [new Document({ pageContent: "text" })];
const vectorStoreFromDocs = await AIVectorStore.fromDocuments(
documents,
new SomeEmbeddings()
);
// Demonstrate common operations
const results = await vectorStore.similaritySearch("query", 5);
This practice ensures developers can quickly understand and implement AI integrations without needing to search through multiple documentation pages or source code.
Use semantic versioning ranges for dependencies instead of “latest” or overly broad ranges. Avoid “latest” as it can cause caching issues during updates. Maintain minimum required version semantics to ensure compatibility - if your code requires features from version 4.4, specify “^4.4” rather than “^4” to prevent runtime errors when using tools like pnpm with resolution-mode set to lowest. When upgrading dependencies, prefer semantic ranges (e.g., “^0.34.2”) over exact version pinning unless there are specific compatibility concerns.
Example:
{
"dependencies": {
// ❌ Avoid - caching issues
"lucide-react": "latest",
// ❌ Avoid - loses minimum version semantics
"zustand": "^4",
// ✅ Good - preserves minimum required version
"zustand": "^4.4",
// ✅ Good - semantic range for upgrades
"lucide-react": "^0.469.0"
}
}
Avoid directly referencing environment variables throughout your codebase. Instead, abstract them into named constants with sensible defaults at module boundaries. This improves readability, makes configuration explicit, and prevents scattered environment variable access.
Create constants that handle the environment variable logic once:
// Good: Abstract with defaults
const DEFAULT_EVAL_MODELS = process.env.EVAL_MODELS
? process.env.EVAL_MODELS.split(",")
: ["gpt-4o", "claude-3-5-sonnet-latest"];
const EXPERIMENTAL_EVAL_MODELS = process.env.EXPERIMENTAL_EVAL_MODELS
? process.env.EXPERIMENTAL_EVAL_MODELS.split(",")
: [];
// Then reference the constants
const models = useExperimental ? EXPERIMENTAL_EVAL_MODELS : DEFAULT_EVAL_MODELS;
// Bad: Direct references scattered throughout
const models = process.env.EVAL_MODELS?.split(",") || ["gpt-4o", "claude-3-5-sonnet-latest"];
Remember that process.env.VARIABLE defaults to undefined when not present - avoid adding unnecessary || undefined or required assertions (!) unless the variable is truly mandatory. Use descriptive constant names that clearly indicate their purpose and scope.
Ensure GitHub Actions workflows are triggered appropriately by configuring branch patterns and path filters to balance CI efficiency with comprehensive coverage. Workflows should run on all relevant branches (not just main) while using path filters to avoid unnecessary executions.
Configure triggers to run on pushes to any branch when you need broad coverage:
on:
push:
branches: ["*"] # or specific patterns like "dev/*"
Use path filters to limit runs to relevant file changes:
on:
push:
branches: ["*"]
paths:
- "lib/**"
- "evals/**"
Avoid overly restrictive triggers that only run on main branch, as this prevents catching issues early in the development cycle. Consider that some changes (like types) may be caught by other build processes (tsc, eslint) and don’t always need separate CI runs.
When implementing knowledge-graph storage/search, proactively prevent expensive work and payload bloat by following these rules:
1) Minimize returned payloads (especially vectors)
_embedding instead of embedding) so queries that don’t need vectors don’t fetch them.2) Make one-time setup idempotent
3) Batch compute for similarity search
4) Bound expensive retrieval early
topk/chunk limits during the query/explore step. Avoid relying on later “context trimming” hacks; constrain the result set at the source.5) Avoid repeated iteration during persistence
Example (index-create guard pattern):
class Adapter:
def __init__(self):
self._chunk_vector_index_created = False
self._entity_vector_index_created = False
def upsert_chunks(self, chunks):
# ... upsert data ...
if not self._chunk_vector_index_created:
self._create_chunk_vector_index()
self._chunk_vector_index_created = True
def upsert_entities(self, entities):
# ... upsert data ...
if not self._entity_vector_index_created:
self._create_entity_vector_index()
self._entity_vector_index_created = True
Maintain consistent and explicit naming conventions across your codebase that reflect:
// INCORRECT: Doesn't indicate dependency on Unstructured API
class DropboxLoader { ... }
// CORRECT: Explicitly indicates dependency
class DropboxUnstructuredLoader { ... }
// INCORRECT: Using deprecated parameter name
const model = new ChatOpenAI({
modelName: "gpt-azure",
});
// CORRECT: Using current parameter name
const model = new ChatOpenAI({
model: "gpt-azure",
});
// INCORRECT: Concatenated words without separation
process.env.GOOGLE_DRIVE_CREDENTIALSPATH
// CORRECT: Words properly separated with underscores
process.env.GOOGLE_DRIVE_CREDENTIALS_PATH
This consistent approach to naming makes your code more maintainable, reduces confusion for other developers, and provides better clarity about component dependencies and behavior.
Ensure proper async/await handling and consider concurrent execution patterns to prevent race conditions and improve performance. When working with asynchronous operations, always use await for promises and avoid mixing promise chains with async/await syntax. Additionally, identify opportunities to run independent operations concurrently rather than sequentially.
Common issues to watch for:
Example of problematic code:
private static loadWebSocket() {
try {
return require('isows').WebSocket;
} catch {
try {
return import('isows').then(m => m.WebSocket); // Missing await, can cause race condition
} catch {
// fallback
}
}
}
Better approach:
private static async loadWebSocket() {
try {
return require('isows').WebSocket;
} catch {
try {
const module = await import('isows'); // Proper await handling
return module.WebSocket;
} catch {
// fallback
}
}
}
For independent operations, prefer concurrent execution:
// Instead of sequential
const sitemapLinks1 = await this.tryFetchSitemapLinks(url, "/sitemap.xml");
const sitemapLinks2 = await this.tryFetchSitemapLinks(url, "/sitemap_index.xml");
// Use concurrent execution
const [sitemapLinks1, sitemapLinks2] = await Promise.all([
this.tryFetchSitemapLinks(url, "/sitemap.xml"),
this.tryFetchSitemapLinks(url, "/sitemap_index.xml")
]);
Always preserve raw network response data early in the processing pipeline before applying any transformations or parsing. Once network data is processed or encoded, critical information may be permanently lost and cannot be recovered later.
This is particularly important for:
Example of the problem:
// BAD: Encoding conversion after string processing
function encodeRawHTML(document: Document): Document {
// At this point, UTF-8 misencoding is "too destructive"
// to recover original Shift_JIS content
const decoder = new TextDecoder(charset);
document.rawHtml = decoder.decode(stringData); // Information already lost
}
// BAD: Using processed HTML for link extraction
linksOnPage = extractLinks(html, urlToScrap); // May miss links from raw content
Move encoding and parsing operations to earlier parts of the stack where you still have access to the raw network buffers. This prevents permanent data loss and ensures all network content is available for processing.
Maintain consistent and proper naming conventions for AI model providers throughout code, documentation, and comments. Use official capitalization (e.g., “OpenAI” not “openai”) and provide clear documentation about which AI services are required versus optional.
When documenting AI model requirements:
Example:
// Good: Proper capitalization and clear requirements
// Stagehand requires OpenAI as a model provider
const stagehand = new Stagehand({
env: "LOCAL",
});
// Documentation should state:
// "NOTE: Stagehand client will default to OpenAI if these are not specified"
This ensures professional presentation, reduces confusion about service requirements, and maintains consistency across the codebase when referencing external AI providers.
Use names that accurately reflect meaning, scope (internal vs external), and responsibility—and keep them consistent with existing/base APIs.
Apply these rules: 1) Internal fields vs user-visible concepts: If a property is implicit/internal, name it consistently with an underscore prefix and ensure all relevant types expose it.
_embedding (not embedding) and ensure ParagraphChunk provides _embedding.2) Match the data type/role to the identifier: Don’t call vectors “keywords” or “text” if the value is embeddings.
keywords: List[List[float]] → subs or embeddings.3) Responsibility-revealing function names: The function name must describe what it actually does.
def _load_doc_graph(self, chunks: List[Chunk]): over _parse_chunks.4) Avoid duplicate/conflicting base names: Don’t introduce new variants of fields already defined by base classes.
_metadata if Knowledge already owns the metadata concept.5) Avoid ambiguous configuration parameter names: Prefer names that won’t be mistaken for other common concepts.
model_alias instead of version when the field is an alias used for registration.6) Use pythonic module/file naming: Ensure filenames follow standard Python conventions (lowercase with underscores, no camel-case file names).
If you’re unsure, ask: “Can another developer infer the value’s meaning and the function’s side effects from the name alone?” If not, rename it.
All retrieval/exploration code (graph + vector/ANN) must be implemented as a staged algorithm with explicit, configurable search hyperparameters, and with correct graph element semantics.
Apply these rules: 1) Make ANN/graph search hyperparameters explicit
2) Limit at the right stage (two-step retrieval)
3) Ensure graph element types are unambiguous
Example pattern (staged retrieval + explicit params):
def search_with_two_stage_explore(graph_store, keywords, *, top_k, ef_search, one_hop_limit):
# Stage 1: constrained exploration (local units)
subgraph = graph_store.explore(
subs=keywords,
limit=one_hop_limit,
search_method="entity_search",
# explicit ANN/graph knobs
top_k=top_k,
hnsw_ef_search=ef_search,
)
# Stage 2: deterministic expansion (structure completion)
chunks = [v.name for v in subgraph.vertices()]
full_structure = graph_store.explore(
subs=chunks,
limit=one_hop_limit,
search_method="path_completion",
)
return full_structure
If implementing graph element classification used by traversal, ensure edge/vertex semantics are explicit:
class GraphElemType(Enum):
# ...
def is_vertex(self):
return self in {GraphElemType.DOCUMENT, GraphElemType.CHUNK, GraphElemType.ENTITY}
def is_edge(self):
return self in {GraphElemType.INCLUDE, GraphElemType.NEXT, ...} # enumerate
Outcome: predictable performance, controllable quality/relevance, and correct traversal behavior for algorithms/search over graphs and vector indexes.
Properly classify dependencies in package.json according to their usage pattern and project guidelines. This ensures correct build behavior, optimizes package size, and prevents dependency conflicts.
Example of correct dependency classification:
// package.json
{
"dependencies": {
// Only runtime requirements
},
"peerDependencies": {
"@libsql/client": "^0.14.0" // Optional integration
},
"devDependencies": {
"@libsql/client": "^0.14.0", // Also needed for testing
"@cloudflare/workers-types": "^4.20240502.0" // Types only
}
}
For third-party integrations, follow the project’s integration guidelines to determine the appropriate dependency type. Avoid adding dependencies when equivalent functionality exists natively.
Prefer passing configuration through constructor parameters rather than setting properties after instantiation. This makes APIs more predictable, enables immutability, and clearly communicates required dependencies at creation time. Additionally, use consistent method naming conventions like .invoke() for primary API methods.
Instead of this:
const loader = new GoogleDriveLoader();
loader.recursive = true;
loader.folderId = "YourGoogleDriveFolderId";
Do this:
const loader = new GoogleDriveLoader({
recursive: true,
folderId: "YourGoogleDriveFolderId"
});
Similarly, when adding methods to an API class, prefer descriptive action names like invoke() over generic terms like call(). This creates a more intuitive API that follows established patterns across the ecosystem.
Maintain clean code organization by eliminating unnecessary abstractions and preventing codebase fragmentation. This applies both at the component level and module level:
// Don't do this:
function InstallationInfo({ children }) {
return <Npm2Yarn>{children}</Npm2Yarn>;
}
// Do this instead:
<Npm2Yarn>{content}</Npm2Yarn>
// Don't do this:
"utils/is_openai_tool": "utils/is_openai_tool",
// Do this instead:
// Add to existing related module like "language_models/base"
This approach reduces code complexity, improves maintainability, and makes the codebase easier to navigate and understand.
Always specify exact version numbers for Docker base images instead of using floating tags like lts or latest. Floating tags can introduce unexpected breaking changes when they automatically update to newer versions, potentially causing build failures or runtime issues in production environments.
Use specific version tags that provide stability and predictable builds:
# Good - pinned to specific version
FROM node:20-slim AS base
# Avoid - floating tag that can change unexpectedly
FROM node:lts-slim AS base
While pinning versions, establish a regular review process to evaluate and upgrade to newer LTS versions when appropriate, ensuring your applications benefit from security updates and performance improvements without surprise breakages.
When implementing caching for functions that accept complex objects (dictionaries with mixed types, Pydantic models, callables), ensure proper cache key generation by filtering out non-serializable objects and converting complex types to serializable formats.
Key requirements:
.dict() or .schema() methodsExample implementation:
def cache_key(request: Dict[str, Any]) -> str:
# Transform Pydantic models and exclude unhashable objects
params = {
k: (v.dict() if isinstance(v, pydantic.BaseModel) else v)
for k, v in request.items()
if not callable(v)
}
return sha256(ujson.dumps(params, sort_keys=True).encode()).hexdigest()
This approach prevents serialization errors like “TypeError:
When introducing new functionality, always include corresponding test coverage that extends existing test infrastructure and validates the feature across multiple scenarios. This ensures robustness and maintains code quality standards.
Key practices:
Example approach:
# When adding streaming functionality, extend existing test server
# tests/test_utils/server/litellm_server.py - add streaming endpoint
# Create integration test in appropriate location
# tests/streaming.py
def test_streaming_endpoint():
# Use existing test infrastructure like litellm_test_server
# Test the complete flow: configure -> run program -> validate stream
stream = streaming_dspy_program(question=question.text)
# Validate streaming response format and content
This approach ensures that new features are thoroughly validated and integrate seamlessly with existing systems, reducing the likelihood of regressions and improving overall system reliability.
Build scripts should remain environment-agnostic and free from personal customizations or assumptions about end-user needs. Avoid including local-specific commands (like clipboard operations) and let consumers make their own decisions about optimizations like minification.
Personal commands like && cat ./lib/dom/bundle.js | pbcopy should be removed as they’re platform-specific and will fail in CI environments or on different operating systems. Similarly, avoid aggressive optimizations like minification in library builds - distributed code should remain readable and debuggable, allowing end users to apply their own build optimizations if needed.
Example of problematic build script:
"bundle-dom-scripts": "esbuild ./lib/dom/index.ts --bundle --outfile=./lib/dom/bundle.js --platform=browser --target=es2015 --minify && cat ./lib/dom/bundle.js | pbcopy"
Better approach:
"bundle-dom-scripts": "esbuild ./lib/dom/index.ts --bundle --outfile=./lib/dom/bundle.js --platform=browser --target=es2015"
This ensures builds work consistently across all environments and maintains code readability for debugging purposes.
When using Next.js dynamic imports, carefully evaluate whether to disable server-side rendering (SSR) based on the component’s purpose and impact on user experience.
Keep SSR enabled (default) when:
Disable SSR (ssr: false) when:
Example:
// ❌ Avoid for layout-affecting components
const CloudBanner = dynamic(() => import('@/features/AlertBanner/CloudBanner'), { ssr: false });
// ✅ Good for error handling
export default dynamic(() => import('@/components/Error'), { ssr: false });
// ✅ Consider for modals
const ModalContent = dynamic(() => import('./ModalContent'), { ssr: false });
The key is preventing layout shifts while ensuring functionality works correctly across SSR and client-side rendering.
Ensure AI model signatures maintain consistency between field types and descriptions, and avoid redundant prompting techniques when the desired behavior is already captured in the signature definition.
When defining AI model signatures, field descriptions should accurately reflect the actual data type. For example, if a field accepts List[dspy.Image], the description should indicate “A list of images” rather than “An image”.
Additionally, avoid using redundant prompting techniques like ChainOfThought when the signature already includes fields that capture the desired reasoning or explanation output.
Example of good practice:
class ColorSignature(dspy.Signature):
"""Output the color of the designated image."""
images: List[dspy.Image] = dspy.InputField(desc="A list of images")
explanation = dspy.OutputField(desc="Reasoning for color detection")
color = dspy.OutputField(desc="Detected color")
# Use simple Predict instead of ChainOfThought since explanation field exists
class ColorModule(dspy.Module):
def __init__(self):
self.prog = dspy.Predict(ColorSignature) # Not dspy.ChainOfThought
This approach reduces confusion, eliminates redundancy, and ensures that AI model interfaces are clear and maintainable.
When integrating AI models and language processing libraries, follow these dependency management best practices:
// RECOMMENDED: Use model-specific packages // Install with: npm install @langchain/openai // “dependencies”: { // “@langchain/openai”: “^x.x.x” // }
2. Don't include AI service libraries as hard dependencies. Follow project contribution guidelines for integrations by making them optional or peer dependencies.
3. When updating AI SDK versions, clearly flag these changes for maintainers to review, as they may impact compatibility or introduce new features that require additional testing.
This approach ensures better maintainability, clearer dependency trees, and more explicit relationships between your project and the AI services it leverages.
---
## Control caching through instantiation
<!-- source: browserbase/stagehand | topic: Caching | language: TypeScript | updated: 2024-11-20 -->
When implementing optional caching functionality, control cache behavior through conditional instantiation at higher abstraction levels rather than adding conditional logic within cache implementations themselves. This approach maintains cleaner separation of concerns and avoids scattered conditional checks throughout cache methods.
Instead of adding enableCaching flags and conditional logic within cache classes:
```typescript
// Avoid this pattern
export class BaseCache<T extends CacheEntry> {
protected enableCaching: boolean;
protected ensureCacheDirectory(): void {
if (this.enableCaching && !fs.existsSync(this.cacheDir)) {
fs.mkdirSync(this.cacheDir, { recursive: true });
}
}
}
Prefer conditional instantiation at the consumer level:
// Prefer this pattern
class LLMProvider {
private cache?: BaseCache<LLMCacheEntry>;
constructor(enableCaching: boolean) {
this.cache = enableCaching ? new BaseCache() : undefined;
}
private async makeCall() {
if (this.cache) {
// Use cache operations
}
}
}
This pattern keeps cache implementations focused on their core responsibility while allowing higher-level components to control when caching is active.
Always use the standardized logging pattern with module-level loggers instead of print statements or direct logging calls. This ensures consistent logging behavior, proper log level control, and better debugging capabilities across the codebase.
The standard pattern is:
import logging
logger = logging.getLogger(__name__)
logger.info("Your message here")
logger.warning("Warning message")
logger.debug("Debug info", exc_info=True) # Include exception info when relevant
Replace print statements with appropriate log levels:
logger.error() or logger.warning() instead of print(e) for exceptionslogger.info() for general informationlogger.debug() for detailed debugging informationIn modules where the dspy logger isn’t available (like dsp folder), follow the same pattern by creating a module-level logger. This maintains consistency and allows proper log level configuration across the entire application.
Always call React hooks at the top level of components and custom hooks to comply with the Rules of Hooks. Handle conditional logic inside hook bodies rather than conditionally calling hooks. When optimizing performance, choose the appropriate hook: use useMemo for computed values and useCallback for function references.
Example of proper hook usage:
function useGlobalShortcut() {
// Call hooks at the top level to comply with the rules of hooks
const chatStore = useChatStore();
const navigate = useNavigate();
const config = useAppConfig();
useEffect(() => {
// Early return if not in environment. This way, the hooks are called unconditionally,
// but the code inside useEffect only runs conditionally
if (!window.__TAURI__) {
return;
}
// Hook logic here...
}, [chatStore, navigate, config]); // Include all dependencies
}
For optimization, prefer useMemo for computed values over useCallback when the result is not a function reference.
APIs should determine behavior based on runtime request characteristics rather than static configuration flags. This enables multiple API providers and models to coexist and ensures proper handling of provider-specific requirements.
Instead of using static configuration flags, inspect the actual request to determine the appropriate behavior:
// ❌ Avoid: Static configuration-based decisions
if (serverConfig.isAzure) {
// Azure-specific logic
}
// ✅ Prefer: Runtime request-based decisions
if (req.nextUrl.pathname.includes("azure/deployments")) {
// Azure-specific logic detected from request path
}
// ❌ Avoid: Model name-based assumptions
if (!chatPath.includes("gemini-pro")) {
// Logic based on model name
}
// ✅ Prefer: Functionality-based detection
if (shouldUseStreamMode(request)) {
// Logic based on actual streaming requirement
}
This approach allows for more flexible API routing, enables multiple providers to work simultaneously, and makes the system more maintainable by reducing coupling between configuration and runtime behavior. Always inspect request paths, parameters, and headers to make informed decisions about API behavior rather than relying on global flags.
Write names that clearly communicate meaning, scope/intent, and project terminology—especially on public APIs/CLI and when calling helpers.
Apply:
endpoint).func(..., api_type=api_type, api_version=api_version) over relying on position._name) for “internal/private by convention”.__name) unless you specifically need name-mangling semantics._ to satisfy linters and show intent (e.g., _logger_with_filter).wandb_logger / WandbLogger) rather than something indistinguishable from general logging.Example:
api_type, api_version = cls._get_api_type_and_version(api_type, api_version)
url = cls._get_url("edits", None, api_type=api_type, api_version=api_version)
def _check_polling_response(...):
... # internal by convention
| Break down complex conditional expressions and control flow into simpler, more readable forms. Use early returns and guard clauses to reduce nesting and avoid unnecessary computations. Avoid chaining multiple conditions with | or && operators when the logic can be made clearer through restructuring. |
Examples of improvements:
if (excludeKeywords.includes(model)) return false;| Replace complex | chains with clearer conditional structures or separate the logic into multiple steps |
This approach makes code easier to understand, debug, and maintain by reducing cognitive load and making the control flow more explicit.
Imports should be organized into distinct groups with proper spacing for better readability. Group all third-party library imports together in one contiguous block, followed by a blank line, then group all local/relative imports in another block. This separation makes it immediately clear which dependencies are external versus internal to the project.
Example of proper import organization:
// Third-party imports (grouped together)
import { describe, expect, it, Mock, vi } from 'vitest';
import { cleanup, fireEvent, render } from '@testing-library/react';
import '@testing-library/jest-dom/vitest';
// Blank line separator
// Local imports (grouped together)
import AgentsList from './agents-list';
import { NEW_SESSION_ID } from '../chat-header/chat-header';
This organization pattern helps developers quickly understand the external dependencies versus internal module relationships, making the code more “polite” to readers and easier to maintain.
When integrating with external AI libraries, models, or services, handle optional dependencies gracefully to avoid affecting users who don’t need those features. Use local imports within class constructors or methods rather than module-level imports, and provide clear error messages when dependencies are missing.
This pattern is essential in AI libraries that integrate with multiple providers (OpenAI, Anthropic, HuggingFace, etc.) where users typically only need a subset of integrations.
Example implementation:
class MistralLM(LM):
def __init__(self, model: str, **kwargs):
try:
import mistralai
except ImportError as err:
raise ImportError(
"The 'mistralai' package is required to use MistralLM. "
"Install it with 'pip install mistralai'."
) from err
super().__init__(model)
self.client = mistralai.Mistral(api_key=kwargs.get('api_key'))
# Instead of module-level imports that affect everyone:
# import mistralai # This would cause errors for all users
Benefits:
Apply this pattern consistently across all optional integrations including embedding models, retrieval systems, tracking libraries, and model providers.
Ensure all documentation follows established templates and includes required sections. When referencing components, add links to their documentation pages. Documentation for each component type (like LLMs or vector stores) should follow its specific template format and include standard sections such as “Overview” with links to conceptual guides and reference tables.
When a component is mentioned in documentation text, include a hyperlink to its own documentation:
// Good example with proper cross-referencing
/**
* The Semantic Cache feature leverages [AzureCosmosDBNoSQLVectorStore](/docs/integrations/vectorstores/azure_cosmosdb_nosql)
* which stores vector embeddings of cached prompts for similarity-based searches.
*
* @see For more details, refer to the [Vector Store conceptual guide](/docs/concepts/vector_stores)
*/
Complete documentation should exist for all public APIs and referenced components. If documentation for a referenced component is missing (like JsonOutputFunctionsParser), create it before finalizing the referencing documentation.
When writing to a database/graph store, make the storage adapter the source of truth for schema details and persist data idempotently.
Apply these rules:
vertex_type, edge_type) in business logic. Provide only domain fields; let the adapter derive types from its schema/config.upsert* APIs for vertices/edges/chunks/relations so repeated loads don’t create duplicates.Example (graph store):
# Bad: callers forcing storage element typing
# graph.upsert_vertex(Vertex(name, description=summary, vertex_type='entity'))
# Good: callers provide only domain data; adapter assigns types
graph.upsert_vertex(Vertex(name, description=summary))
# And when building relations from chunks/documents, route through adapter upsert helpers
graph_adapter.upsert_document_include_chunk(chunk=chunk, doc_vid=doc_vid)
graph_adapter.upsert_chunk_next_chunk(prev_chunk=prev, next_chunk=chunk)
Example (DB config principle):
When updating technical docs, avoid duplicating environment-specific setup or repeated troubleshooting steps. Prefer linking to the canonical upstream documentation for shell/env configuration, and keep only minimal project-specific commands (e.g., where you truly provide “permanent activation” instructions). Also consolidate identical “fix-it” guidance into a single canonical section, using cross-links instead of repeating the same snippet.
Example (keep only required project-specific commands, link the rest):
# Minimal project-specific permanent activation
register-python-argcomplete openai >> ~/.bashrc
register-python-argcomplete openai >> ~/.zshrc
# For other shells or temporary activation, link to upstream docs
# (replace duplicated instruction blocks with the appropriate argcomplete docs link)
Example (deduplicate troubleshooting text):
Before assuming performance issues exist, measure actual execution time and resource usage. When performance problems are confirmed, eliminate unnecessary operations like redundant initializations, blocking operations, or wasteful resource usage.
Use performance measurement tools to validate concerns:
function escapeBrackets(text: string) {
let begin_time = performance.now();
const pattern = /(```[\s\S]*?```|`.*?`)|\\\[([\s\S]*?[^\\])\\\]|\\\((.*?)\\\)/g;
let res = text.replace(pattern, (match, codeBlock, squareBracket, roundBracket) => {
// ... processing logic
});
let endTime = performance.now();
console.log(`escapeBrackets, string length=${text.length}, time consumed=${endTime - begin_time} ms`);
return res;
}
Common wasteful operations to eliminate:
Modern JavaScript engines often optimize common patterns like regex compilation, but measurement reveals the actual impact rather than assumptions.
Tests should be isolated from the production environment to prevent side effects and ensure reproducibility. This principle has two main applications:
Use proper temporary files: Instead of writing test files to the current directory where they might overwrite real files, use the tempfile module to create isolated test files.
Establish correct directory context: Ensure tests run in the appropriate directory context to prevent location-dependent failures.
Example:
# Good: Use temporary files instead of hardcoded paths
import tempfile
message_file_path = tempfile.mktemp()
main(["--message-file", message_file_path], input=DummyInput(), output=DummyOutput())
# Good: Explicitly set the directory context for tests
with change_dir(testdir):
# Test code runs in the correct context
# ...
Following these practices prevents tests from accidentally modifying real files and ensures they’ll run consistently regardless of the current working directory.
Maintain consistency in styling approaches within components and across the codebase. Avoid mixing className and inline styles in the same component - choose one approach and stick with it throughout the component. When working with reusable UI library components, keep them generic by using className for styling rather than adding component-specific inline styles that could pollute the library’s interface.
For example, instead of mixing approaches:
// Avoid mixing styles
<div style={{ position: "relative" }}>
<pre
ref={ref}
style={{
maxHeight: collapsed ? "400px" : "none",
overflow: "hidden",
}}
>
<span className="copy-code-button">
Use a consistent approach with className:
// Consistent className usage
<div className="code-container">
<pre
ref={ref}
className={`code-block ${collapsed ? 'collapsed' : 'expanded'}`}
>
<span className="copy-code-button">
This improves maintainability, keeps styling logic centralized in CSS files, and maintains clean separation between UI library components and application-specific styling.
Maintain consistent package manager usage throughout the project lifecycle. When a project uses yarn (indicated by yarn.lock), avoid committing npm’s package-lock.json file, as having both lock files can cause dependency resolution conflicts and inconsistent builds across different environments.
Key practices:
Example violation:
# Project structure showing both lock files (problematic)
├── package.json
├── yarn.lock # Using yarn
└── package-lock.json # Should not exist when using yarn
This practice ensures reproducible builds and prevents confusion about which package manager and dependency versions should be used in different environments.
Variable, method, and type names should precisely reflect their actual content, purpose, or scope. Names that misrepresent what they contain or do create confusion and make code harder to understand and maintain.
Ensure that:
PartialLocaleType for partial implementations, not the full LocaleType)const no: LocaleType for Norwegian locale, not const en: LocaleType)Example of problematic naming:
// Misleading - suggests full locale but may be partial
import { LocaleType } from "./index";
// Confusing - Norwegian locale named as English
const en: LocaleType = {
// Norwegian translations...
};
Example of semantically accurate naming:
// Clear - indicates partial implementation
import { PartialLocaleType } from "./index";
// Accurate - matches the actual locale
const no: LocaleType = {
// Norwegian translations...
};
// Explicit default parameter
export function getHeaders(ignoreHeaders: boolean = false) {
// ...
}
This practice makes code self-documenting and reduces cognitive load when reading and maintaining the codebase.
When authoring AI/LLM tutorials in Jupyter notebooks, ensure dependency installation is done with correct notebook syntax and that nearby explanatory text is unambiguous.
pip lines).Example:
# In a notebook cell (ipynb), use the magic:
%pip install langchain_community
# And keep narrative wording clear when describing state:
# "...wraps the model and adds to this message history..."
在组件/页面代码中保持表达清晰、类型明确,避免冗余与 any。
flag ? true : false,可直接传布尔值本身。
// bad
multiple={data.is_list ? true : false}
// good
multiple={data.is_list}
any 作为 props 或关键数据类型;为 props、组件内数据(如 importData)补充明确的 TypeScript 类型。
type ImportData = {/* 字段按实际补齐 */};
const Canvas: React.FC<{ importData: ImportData | null }> = ({ importData }) => {
// ...
return null;
};
这些规则能提升可读性、减少潜在类型错误,并使代码更易维护。
Design configuration with clear semantics and appropriate scope. Avoid global constants for values that can be handled locally, and ensure configuration parameters have logical, non-contradictory meanings.
Avoid unnecessary global configuration constants:
# Instead of:
DEFAULT_PORT = 8000
DEFAULT_INDEX = True # Global constants
# Consider handling defaults in-context:
def setup_server(port=8000, enable_indexing=False):
# Handle defaults locally where they're used
Design clear configuration interfaces:
# Avoid contradictory parameters:
# Bad: Indexer(perform_indexing=True, force_disable_indexing=True)
# Better: Handle configuration logic at application level:
if params.index and not params.force_disable:
indexer = Indexer(index_json_file=path)
# Use indexer
else:
# Skip indexing entirely
Configuration should be intuitive - parameters shouldn’t require mental gymnastics to understand their combined effect. Keep configuration logic at the appropriate architectural level rather than pushing contradictory options down to individual components.
Always externalize configuration values rather than hardcoding them directly in the code. This improves maintainability, enables easier configuration changes, and ensures consistency across the codebase.
Key practices:
Example:
# Instead of this:
main_system = """Act as an expert software developer."""
# Do this:
from . import prompt_manager
yaml_prompt_entry = prompt_manager.get_prompt_value('ComponentName', 'main_system')
# And when reading files, respect user configuration:
# Instead of:
with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()
# Use utilities that honor user settings:
content = io.read_text(file_path) # Respects --encoding setting
This approach makes the codebase more flexible, easier to maintain, and respectful of user-defined settings.
Proactively identify and prevent common security vulnerabilities in code, particularly around sensitive data handling and input validation. Avoid logging sensitive information like API keys, tokens, or passwords that could be exposed in log files. Implement robust input validation using proper parsing methods rather than simple string operations that can be bypassed.
For sensitive data logging:
// ❌ Avoid - exposes sensitive data
console.log("[Auth] use system api key", systemApiKey);
// ✅ Better - log without sensitive details
console.log("[Auth] use system api key");
For input validation:
// ❌ Avoid - can be bypassed with crafted URLs
if (!endpoint || !endpoint.endsWith("upstash.io")) {
// ✅ Better - use proper URL parsing
try {
if (!(new URL(endpoint).hostname.endsWith('.upstash.io'))) {
throw new Error('Invalid endpoint');
}
} catch (e) {
throw new Error('Invalid URL format');
}
Always consider how an attacker might exploit weak validation or gain access to sensitive information through logs, error messages, or other data exposure points.
When implementing sorting algorithms for collections, ensure stable and predictable ordering to avoid inconsistencies from operations like Object.values(). Use multi-level sorting criteria and consider sequence-based approaches for complex ordering requirements.
Key principles:
Example implementation:
const sortModelTable = (
models: ReturnType<typeof collectModels>,
rule: "custom-first" | "default-first",
) =>
models.sort((a, b) => {
// Primary sort: custom vs default
let aIsCustom = a.provider?.providerType === "custom";
let bIsCustom = b.provider?.providerType === "custom";
if (aIsCustom !== bIsCustom) {
return aIsCustom === (rule === "custom-first") ? -1 : 1;
}
// Secondary sort: by provider type, then model name
if (a.provider && b.provider) {
const providerTypeComparison = a.provider.providerType.localeCompare(b.provider.providerType);
if (providerTypeComparison !== 0) {
return providerTypeComparison;
}
return a.name.localeCompare(b.name);
}
return a.name.localeCompare(b.name);
});
For even more stability, use explicit sequence numbers:
// Assign sequence numbers for predictable ordering
let customSeq = -1000; // Custom models get negative numbers (higher priority)
let defaultSeq = 1000; // Default models get positive numbers
const modelWithSorted = {
...model,
sorted: isCustom ? customSeq++ : defaultSeq++
};
This approach ensures consistent ordering regardless of the underlying data structure’s iteration order and provides clear, maintainable sorting logic.
When modifying configuration schemas or adding new configuration options, always ensure backward compatibility with existing deployments. Long-running systems with many user deployments require smooth migration paths from old configurations to new ones.
Key practices:
Example from model configuration handling:
// Check for new format first
if (defaultModel.includes('@')) {
// New format: model@provider
if (defaultModel in modelTable) {
modelTable[defaultModel].isDefault = true;
}
} else {
// Old format: just model name - find first matching model
for (const key in modelTable) {
if (key.split('@').shift() === defaultModel) {
modelTable[key].isDefault = true;
break;
}
}
}
This approach ensures that users with existing configurations can continue using the system without forced updates, while new users benefit from improved configuration options.
Choose names that reflect purpose and meaning rather than visual appearance, position, or implementation details. This improves code clarity, supports internationalization, and makes the codebase more maintainable.
Avoid positional or appearance-based names like right, left, top that break in different contexts (RTL languages, responsive layouts). Instead, use semantic names that describe the role or function.
Example:
// ❌ Avoid positional naming
const useStyles = createStyles(({ css }) => ({
right: css`
display: flex;
`,
}));
// ✅ Use semantic naming
const useStyles = createStyles(({ css }) => ({
assistant: css`
display: flex;
`,
user: css`
display: flex;
`,
}));
// ❌ Avoid generic labels
<Button title="润色中">Stop</Button>
// ✅ Use descriptive, context-aware labels
<Button title="语音输入">Stop</Button>
This approach ensures your code works across different languages, layouts, and contexts while making the intent clear to other developers.
When adding new files or components to the project, ensure that documentation configuration is updated accordingly. This includes adding new files to TypeDoc options in tsconfig.json to maintain complete API documentation coverage. Additionally, clearly mark deprecated components and direct developers to use the recommended alternatives instead of extending deprecated functionality.
Example:
// When adding a new file like document_loaders/fs/md.ts
// Remember to update the TypeDoc configuration in tsconfig.json:
"typedocOptions": {
"entryPoints": [
// existing entries
"document_loaders/fs/md.ts"
]
}
// For deprecated components, add clear documentation:
/**
* @deprecated This entrypoint is deprecated.
* Please use the community integration instead.
*/
This practice ensures comprehensive documentation coverage and provides clear guidance for developers, preventing them from extending deprecated features and helping them locate the proper integration points for new functionality.
Implement error handling that is both architecturally localized and contextually specific to provide better user experience and system resilience. Use localized error boundaries to prevent cascading failures while ensuring error messages are specific to the actual problem and provide actionable guidance.
For architectural design, prefer localized error boundaries over relying solely on global error handlers. This allows different sections of the application to fail independently without affecting other areas, as demonstrated in the discussion: “外面是全页面的,里面加的话可以做到分区出现” (sectional error display) and “其他地方就不会挂掉” (other areas won’t crash).
For error messaging, replace generic error messages with specific, actionable ones. Instead of broad messages like “请求服务出错” (service request error), use specific messages like “未找到该本地模型,请通过 Ollama 下载后重试” (model not found, please download via Ollama and retry). This helps users understand exactly what went wrong and what they can do to resolve it.
Example implementation:
// Localized error boundary for specific feature
<ErrorBoundary fallback={<InvalidOllamaModel />}>
<ConversationComponent />
</ErrorBoundary>
// Specific error component with actionable message
function InvalidOllamaModel() {
return (
<div>
<p>未找到该本地模型,请通过 Ollama 下载后重试</p>
<button>下载模型</button>
</div>
);
}
When implementing features that interact with AI models, consider the behavioral differences between various models and adjust parameters accordingly. Different AI models have distinct characteristics such as output speed, token generation patterns, and response formats that can significantly impact user experience.
For example, streaming chat interfaces need different auto-scroll thresholds for different models:
// Consider model output characteristics
const getScrollThreshold = (modelType: string) => {
// Fast models (GPT-3.5, Sonnet, Groq) output in bursts
if (modelType.includes('gpt-3.5') || modelType.includes('sonnet')) {
return 80; // Higher threshold for burst output
}
// Slower models (Gemini) output character by character
return 50; // Lower threshold for steady output
};
<Virtuoso
atBottomThreshold={getScrollThreshold(currentModel)}
// ... other props
/>
This approach prevents common issues like auto-scroll failing when fast models output multiple lines simultaneously, or performance problems when not optimizing for model-specific behaviors. Always test with different model types to ensure consistent user experience across various AI providers.
When integrating with external APIs, explicitly handle version differences and use parameterized configurations instead of hardcoded values. Different API versions often require different request methods, endpoints, or parameters, so version-specific logic should be clearly defined to prevent incorrect API calls.
Key practices:
Example of explicit version handling:
# Good: Explicit version handling
if self.api_model in ["claude-instant", "claude-2", "claude-2.1"]:
# Use completions.create() for older models
response = client.completions.create(...)
else:
# Use messages.create() for Claude-3 family
response = client.messages.create(...)
Example of parameterized configuration:
# Good: Parameterized with fallback
api_version = cfg.get("OPENAI_API_VERSION", "2024-02-01")
self.client = AzureOpenAI(
api_key=cfg["AZURE_OPENAI_API_KEY"],
azure_endpoint=cfg["AZURE_OPENAI_ENDPOINT"],
api_version=api_version
)
# Avoid: Hardcoded version
self.client = AzureOpenAI(..., api_version="2024-02-01")
This approach prevents API compatibility issues, makes version updates easier to manage, and ensures the correct API interface is used for each version.
When importing multiple items from the same module, use separate import statements instead of combining them on a single line. This improves code readability and makes it easier to track individual imports during code reviews and refactoring.
Instead of:
from refact_webgui.webgui.selfhost_model_resolve import completion_resolve_model, resolve_model_context_size, resolve_tokenizer_name_for_model
Use:
from refact_webgui.webgui.selfhost_model_resolve import completion_resolve_model
from refact_webgui.webgui.selfhost_model_resolve import resolve_model_context_size
from refact_webgui.webgui.selfhost_model_resolve import resolve_tokenizer_name_for_model
This approach makes each import explicit, reduces line length, and makes it easier to add, remove, or modify individual imports without affecting others.
Choose identifier names that avoid system compatibility issues and follow proper naming conventions. Avoid reserved words, system-problematic names, and invalid characters that can cause issues across different platforms or violate language standards.
Key guidelines:
Example from the codebase:
# Problematic - 'aux' is reserved on Windows
from self_hosting_machinery.finetune.scripts.aux.finetune_filter_status_tracker import FinetuneFilterStatusTracker
# Better - use full descriptive name
from self_hosting_machinery.finetune.scripts.auxiliary.finetune_filter_status_tracker import FinetuneFilterStatusTracker
# Problematic - spaces in identifier validation
if not re.match("^[a-zA-Z0-9_ -]*$", v):
# Better - exclude spaces from allowed characters
if not re.match("^[a-zA-Z0-9_-]*$", v):
This prevents deployment issues, ensures cross-platform compatibility, and maintains consistent identifier standards across the codebase.
Ensure AI models use configuration settings that match their specific architecture and requirements. Different model families (e.g., BigCode vs LLaMA) require different tokenizer configurations, memory management settings, and parameter mappings. Avoid using generic or copy-pasted configurations across different model types.
Key areas to verify:
Example of proper model-specific configuration:
# Wrong - using BigCode tokenizer config for LLaMA model
"tokenizer": {
"eot_idx": 0, # BigCode specific
}
# Right - check model family and use appropriate config
if model_family == "llama":
tokenizer_config = load_llama_tokenizer_config()
elif model_family == "bigcode":
tokenizer_config = load_bigcode_tokenizer_config()
# Enable checkpointing for large models
"force_enable_checkpointing": model_size > threshold
Always validate that configuration parameters match the target model’s architecture to prevent runtime errors and ensure optimal performance.
All API endpoints must implement proper authorization checks before processing requests, especially when authentication mechanisms like tokens are available. When adding new API routes, verify that appropriate authorization validation is in place to prevent unauthorized access to sensitive functionality.
Example implementation pattern:
async def _rh_stats(self, account: str = "user"):
# Add authorization check before processing
if not self._validate_admin_token():
raise HTTPException(status_code=401, detail="Unauthorized")
if not self._stats_service.is_ready:
# ... rest of endpoint logic
Reference existing authorization patterns in your codebase (such as CompletionsRouter) to ensure consistency in how authorization is implemented across different endpoints. This prevents security vulnerabilities where sensitive data or operations could be accessed without proper authentication.
Ensure API endpoints adhere to established design conventions including proper HTTP methods, authorization requirements, and clean route organization. Use GET for data retrieval operations and include appropriate authorization headers for protected endpoints. Avoid creating unnecessary routers when prefixes can be incorporated directly into route definitions.
For HTTP methods and security:
# Instead of POST for data retrieval
self.add_api_route('/rh-stats', self._rh_stats, methods=["POST"])
# Use GET with authorization
self.add_api_route('/rh-stats', self._rh_stats, methods=["GET"]) # + authorization header
For route organization:
# Instead of creating separate routers with prefixes
CAPSRouter(prefix="/v1", ...)
# Incorporate prefix directly into route
self.add_api_route("/v1/completions", self._completions, methods=["POST"])
This approach maintains RESTful principles, improves security posture, and simplifies codebase organization by reducing unnecessary abstraction layers.
When writing documentation in code (comments, docstrings, example snippets), ensure every instruction and external link precisely matches the actual package extras and the implemented service/provider.
Apply this checklist:
pip syntax for editable installs and extras, and confirm the package name.
pip install -e ".[openai]"pip install "db-gpt[openai]"Example (corrected install snippet):
# Install extra support
pip install -e ".[openai]"
# or
pip install "db-gpt[openai]"
If you’re unsure which doc/link is correct, verify against the project’s packaging metadata (extras) and the exact provider SDK you’re calling.
When constructing connection strings/URIs that embed user credentials, always URL-encode username/password (and other URI components as needed) using an encoder that safely handles reserved characters. Avoid urllib.parse.quote for credentials where characters like @ and # may appear; prefer quote_plus.
Example:
from urllib.parse import quote_plus
db_url = (
f"doris://{quote_plus(user)}:{quote_plus(pwd)}@{host}:{port}/{db_name}"
)
This prevents malformed URIs and ensures credentials are interpreted correctly and securely by the client/driver.
Implement intelligent model selection mechanisms that adapt to different scenarios instead of hardcoding specific AI models. Create abstraction layers that can:
For example, instead of directly referencing specific models:
# Avoid this
async for msg_chunk in sdk.models.gpt350613.stream_chat(context, functions=functions):
# ...
# Prefer this
model = get_model_with_capability("function_calling")
async for msg_chunk in model.stream_chat(context, functions=functions):
# ...
Or implement intelligent upgrade paths:
# Allow models to handle their own upgrades based on context requirements
model_to_use = await model_to_use.maybe_upgrade(required_context_length)
This approach makes your AI code more maintainable, adaptable to new models, and cost-efficient while still meeting functional requirements.
When retrieving configuration values like API keys or environment variables, include helpful error messages that guide users on how to fix missing configurations. Consider centralizing configuration retrieval logic in the appropriate classes based on their usage patterns.
For example, instead of just reporting a missing environment variable:
# Better approach with helpful guidance
async def get_api_key(self, env_var: str) -> str:
# Provide a helpful default message that references the specific environment variable
prompt = f"Please add your {env_var} to the .env file"
return await self.ide.getUserSecret(env_var, prompt=prompt)
This approach not only handles the configuration retrieval but also improves developer experience by providing clear guidance when configuration issues arise. For configuration logic that’s specific to certain components (like Models), consider housing that logic within those component classes rather than in general utility methods.
Proxy endpoints that forward requests to external services can be exploited by malicious actors if left unsecured. Always implement proper authentication, authorization, and destination validation for proxy endpoints, especially in production deployments.
Consider these security measures:
Example of a potentially vulnerable proxy configuration:
// next.config.mjs - Unsecured proxy
async rewrites() {
const ret = [
{
source: "/api/proxy/:path*",
destination: "https://api.openai.com/:path*", // Open proxy - can be abused
}
];
}
Instead, secure the proxy with proper authentication and validation in your API route handlers, and consider environment-specific security controls for production deployments.
Always validate that parameters contain expected types and values within safe boundaries, not just null/undefined checks. Optional parameters can receive unexpected types (like event objects), and numeric parameters need boundary validation to prevent invalid operations.
For optional parameters, verify the actual type matches expectations:
// Bad: assumes i is either number or undefined
deleteSession(i?: number) {
const index = i ?? get().currentSessionIndex; // fails when i is an event object
}
// Good: validate the parameter type
deleteSession(i?: number) {
const index = (typeof i === 'number') ? i : get().currentSessionIndex;
}
For numeric operations, use boundary checks to prevent invalid results:
// Bad: can create negative indices when historyMessageCount is 0
session.messages.slice(n - config.historyMessageCount)
// Good: ensure non-negative starting index
session.messages.slice(Math.max(0, n - config.historyMessageCount))
This prevents runtime errors from undefined values and invalid array operations.
When implementing HTTP/multipart requests and streaming (SSE/chunked) parsing with aiohttp, follow these rules:
Example patterns:
# Multipart: use aiohttp primitive rather than ad-hoc dict encoding
writer = aiohttp.MultipartWriter()
# ... append parts to writer ...
# Response lifecycle: release to pool (avoid breaking pooling semantics)
resp = await session.request(...)
try:
# read/parse as needed
...
finally:
if not resp.closed:
resp.release() # return connection to pool
# Streaming parser: be chunk-boundary agnostic
async def parse_stream_async(reader):
async for chunk in reader:
for line in chunk.splitlines():
# handle b"data: " prefix / DONE sentinel as appropriate
...
When adding Azure Active Directory authentication (Security), make token acquisition and dependency responsibility explicit and align it with your SDK’s lifecycle.
azure.identity) and pass it into the request.api_type = "azure_ad" and provide the acquired credential token as api_key (used for request headers).Example (documented flow):
from azure.identity import DefaultAzureCredential
import openai
default_credential = DefaultAzureCredential()
# Acquire token for Azure Cognitive Services
token = default_credential.get_token("https://cognitiveservices.azure.com")
openai.api_type = "azure_ad"
openai.api_key = token.token
This keeps the authentication flow predictable (caller-owned, token-only passthrough) and reduces the risk of surprising security behavior or broken SDK integration.
Implement token-efficient patterns when working with AI models to optimize costs and performance. Key practices include:
Example of efficient batching with OpenAI:
// Inefficient: Multiple separate calls
const results = await Promise.all(
inputs.map(input => model.generate(input))
);
// Efficient: Single batched call
const results = await model.generate(
[promptValue],
{ n: inputs.length } // OpenAI charges input tokens only once
);
// For accurate token counting:
const tokenCount = await model.getNumTokensFromMessages(messages);
This approach can significantly reduce costs, especially for use cases with high input token counts relative to output. Different providers may offer varying batching capabilities - consult their documentation for optimal usage patterns.