Agent skill

OpenObserve ESLint and TypeScript Fixes

by openobserve in openobserve/openobserve

A playbook for fixing ESLint and TypeScript errors in the OpenObserve web frontend, with rule-by-rule guidance and typing conventions.

AGPL-3.0Auto-check passedDevelopment

Install OpenObserve ESLint and TypeScript Fixes

skills CLI
$ npx skills add openobserve/openobserve --skill eslint-error-handling -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install openobserve/openobserve eslint-error-handling --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/openobserve/openobserve.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/eslint-error-handling .claude/skills/eslint-error-handling && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
eslint-error-handling
GitHub stars
22k
Token cost
~5.1k tokens
SKILL.md length
1,373 words
Files
1
Skills in repo
3
Repo updated
First seen
Licence
AGPL-3.0

At a glance

A playbook for fixing ESLint and TypeScript errors in the OpenObserve web frontend, with rule-by-rule guidance and typing conventions.

  • Works in 10 steps: Golden rules (apply to every fix) → Typing conventions — inline vs dedicated… → Unused code —… → …
  • Fixing lint or type-check errors in the OpenObserve web frontend
  • SKILL.md covers 0. Golden rules (apply to…, 1. Typing conventions — inline…, 2. Unused code —… and 3. Real-bug rules (Bucket 1 —…, plus 6 more sections
  • Calls npm, npx and node

What it does

The stack is Vue 3, TypeScript, an ESLint flat config and Prettier, and the gates are npm run lint:ci and npm run type-check:app (vue-tsc), both of which must stay at 0 errors. Six golden rules apply to every fix: never use any, prefer types at the declaration site over as casts, keep type-only fixes from changing runtime behavior, use strict equality only, keep comments to one or two lines, and fix rather than suppress, with eslint-disable or @ts-expect-error reserved for genuine false positives and given a reason.

A typing section says where a type should live by scope: inline for a one-off shape, a local Props interface or a *.types.ts sibling for component props, a feature-level types file once two or more files share a shape, and src/ts/interfaces for cross-cutting domain models and for types that mirror backend API responses, derived from the Rust struct. Extending an existing interface is preferred to inventing a parallel one. The description adds rule-by-rule before and after examples and conventions for unused code, Vue-specific rules, casts and formatting.

When your agent uses it

  • Fixing lint or type-check errors in the OpenObserve web frontend
  • Deciding whether a new type belongs inline or in a shared file
  • Replacing any and as casts with proper types
  • Writing new Vue code that already meets the repo's lint standard

Example prompts

  • “Fix the vue-tsc errors in web/src/components/alerts without using any.”
  • “Run lint:ci for the web app and fix the errors rule by rule.”
  • “Where should the type for this search response go, inline or in src/ts/interfaces?”

Requirements

  • Node.js with the web/ project dependencies installed

Workflow steps

10 steps, taken from the step headings in SKILL.md.

  1. Golden rules (apply to every fix)
  2. Typing conventions — inline vs dedicated file
  3. Unused code — @typescript-eslint/no-unused-vars (the big bucket)
  4. Real-bug rules (Bucket 1 — fix each by hand)
  5. Low-risk / mechanical (Bucket 2)
  6. Why some rules stay OFF (don't "fix" these)
  7. TypeScript compiler errors (type-check:app)
  8. Formatting (Prettier)
  9. Workflow
  10. Gradual rollout — flipping a rule warn → error

What it can do on your machine

Read from SKILL.md and the folder at commit 0e9ab49. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm
    • npx
    • node

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npm and npx, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

OpenObserve ESLint and TypeScript Fixes loads about 5.1k tokens when it runs. Until then it costs about 99 tokens; SKILL.md has 1,373 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~99
When it runs · the whole SKILL.md, loaded when a task matches
~5.1k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from openobserve/openobserve at commit 0e9ab49, republished under its AGPL-3.0 licence (© openobserve). 1,373 words, ~5,083 tokens.

Download SKILL.mdSave it as .claude/skills/eslint-error-handling/SKILL.md (or your agent's skills folder).
name
eslint-error-handling
description
Playbook for resolving ESLint and TypeScript errors in the OpenObserve web/ frontend (Vue 3 + TS). Rule-by-rule fixes with before/after examples, plus conventions for typing (inline vs dedicated file), unused code, Vue-specific rules, casts, and formatting. Use when fixing lint/type-check errors or writing new web code so fixes are consistent with the codebase standard.

ESLint & TypeScript Error Handling — web/

Stack: Vue 3 + TypeScript + ESLint flat config (eslint.config.js) + Prettier. Gates: npm run lint:ci (ESLint; -- --quiet for errors-only) and npm run type-check:app (vue-tsc against tsconfig.app.json) — both must stay at 0 errors. Rollout plan & rationale: see the lint & type-check strictness rollout design doc.

0. Golden rules (apply to every fix)

  1. Never use any. No : any, as any, any[], <any>. Enrich an interface, narrow with unknown + a type guard, or derive the type. If a value is truly dynamic, use unknown and narrow at use.
  2. Prefer declaration-site types over as casts. Type the ref/variable/prop/ function-return at its declaration so the cast disappears. Casts are a last resort.
  3. Type-only fixes must not change runtime behavior. A cast/assertion is the right tool when the alternative alters behavior (adding typeof/String()/branches to satisfy the compiler is a behavior change — don't).
  4. Strict equality only (===/!==, never ==/!=).
  5. Comments: max 1–2 lines, stating only the non-obvious constraint.
  6. Fix, don't suppress. // eslint-disable / @ts-expect-error only for genuine false positives (e.g. an intentional control-char regex), with a reason after --.

1. Typing conventions — inline vs dedicated file

Decide where a type lives by scope, not habit:

SituationWhere the type goes
Used in one function/block, small shapeInline at the declaration: const x: { id: string } = …
A component's props/emits/slotsInline in defineProps<…>() / a local interface Props in the same SFC; for a design-system component use its *.types.ts sibling
Shared by 2+ files in the same featureA types.ts (or feature.types.ts) next to the feature
Cross-cutting domain model (Stream, Alert, Dashboard, SearchObject…)src/ts/interfaces/* (barrel @/ts/interfaces)
Mirrors a backend API responseDerive from the Rust struct and put it in src/ts/interfaces/*; name it after the BE type

Rules of thumb:

  • Don't create a file for a one-off shape — inline it.
  • Do extract to a shared interface the moment a second file needs the same shape (duplicate inline shapes drift).
  • Prefer extending an existing interface over inventing a parallel one (that's how the StreamField conflict happened — multiple incompatible shapes).
  • For an empty-array field in a state literal, type the element at the declaration: field: [] as string[] (this is declaration-site typing, not a value cast).
ts
// ❌ inline shape duplicated across files → they drift
function a(u: { id: string; name: string }) {}
function b(u: { id: string; name: string }) {}

// ✅ shared interface in src/ts/interfaces/user.ts
export interface User { id: string; name: string }
1.1 Typing an API response — ALWAYS check the backend, never any

When you hit const res: any = await someService.call(...) or (res as any).field, do not cast — trace the response to the Rust struct and mirror it as an interface. The backend is the source of truth for API shapes.

Steps:

  1. FE service → endpoint. Open the service method to get the HTTP path.
    ts
    // web/src/services/stream.ts
    nameList: (org) => http().get(`/api/${org}/streams`)   // GET /api/{org}/streams
  2. Endpoint → Rust handler + struct. Search the backend (repo root src/, Rust):
    grep -rn "streams" src/handler/http/request/stream/mod.rs   # find the handler
    grep -rn "pub struct ListStream" src/                        # find the response struct
    rust
    // src/common/meta/stream.rs
    pub struct ListStream { pub list: Vec<Stream>, pub total: usize }
    pub struct Stream { pub name: String, pub stream_type: StreamType,
                        pub schema: Vec<StreamField>, /* … */ }
  3. Mirror it as a TS interface in src/ts/interfaces/* (reuse one if it already exists — grep -rn "interface Stream" web/src/ts/interfaces first). Map Rust → TS: String→string, usize/i64/f64→number, bool→boolean, Vec<T>→T[], Option<T>→T | undefined (or field?:), HashMap<K,V>→Record<K, V>, enum→union.
    ts
    // web/src/ts/interfaces/stream.ts
    export interface ListStream { list: Stream[]; total: number }
    export interface Stream {
      name: string;
      stream_type: "logs" | "metrics" | "traces";
      schema: StreamField[];
    }
  4. Use it at the declaration (the service returns unknown/AxiosResponse, so one boundary annotation, then no more casts):
    ts
    // ❌ const res: any = await StreamService.nameList(org);
    //    if (res.data.list.length) …           // untyped, cast-ridden
    // ✅
    const res = await StreamService.nameList(org);
    const data = res.data as ListStream;         // one boundary annotation
    if (data.list.length > 0) { data.list.map((s) => s.name); }  // fully typed

Field names must match the wire format exactly (usually snake_case from serde) — don't rename to camelCase in the interface, or access silently returns undefined. Only include the fields the FE actually reads; add more as needed.

1.2 Untyped API calls in this repo — find them & where the wins are

Only 18 / 57 service files declare any response type, so most calls come back any. Find every untyped awaited API result (excludes dynamic await import() — those are module imports, not API calls):

bash
grep -rnE ':\s*any\s*=\s*await' web/src --include='*.ts' --include='*.vue' \
  | grep -v '.spec.' | grep -v 'await import('

At time of writing that's ~64 sites, and they cluster hard — fix the hot functions once (in their composable/service) and dozens of call sites become typed for free:

FunctionCall sitesEndpoint (trace this to the Rust struct)
getStreams (useStreams)27GET /api/{org}/streams → ListStream { list: Vec<Stream>, total }
getStream (useStreams)8GET /api/{org}/streams/{name}/schema → Stream
getDashboard2GET /api/{org}/dashboards/{id}
commonService.list_Folders / dashboardService.list_Folders2GET /api/{org}/folders
long tail (users, roles, pipelines, reports, org settings, …)1 eachsee each service file for its url

Workflow: give useStreams.getStreams / getStream a real return type (via §1.1), delete the : any at the 35 call sites, then work down the long tail. Type at the source (the service/composable return), not at each call site.

2. Unused code — @typescript-eslint/no-unused-vars (the big bucket)

Single source of truth for unused code (core no-unused-vars and TS noUnusedLocals stay off).

DELETE is the default fix. _-prefix is a narrow last resort for FUNCTION PARAMETERS ONLY — never _-prefix an import, a local, or a function/const, because that just hides dead code instead of removing it.

ts
// ❌ unused import → remove it (or just the one specifier)
import { computed, ref, watch } from "vue"; // watch never used
import { computed, ref } from "vue";        // ✅

// ❌ unused local
const result = compute();                   // never read
compute();                                  // ✅ side-effect call → keep call, drop binding
                                            // ✅ no side effects → delete the line entirely

// ❌ unused standalone function/const — DELETE it (dead code)
const _getInitials = () => …;               // ❌ `_`-prefix does NOT make it "used"
// ✅ verify no caller (grep the name), then remove the whole declaration.

// PARAMETERS:
// ❌ unused TRAILING param → REMOVE it, don't `_`-prefix
arr.map((item, index) => item.id);          // index unused
arr.map((item) => item.id);                 // ✅ drop it
watch(src, (_newVal, _oldVal) => { … });    // ❌ both unused & trailing
watch(src, () => { … });                    // ✅ drop them
// ❌ unused DESTRUCTURED element (e.g. setup's ctx) → remove the key, don't rename
setup(props, { emit: _emit, expose }) {}    // ❌ emit unused
setup(props, { expose }) {}                 // ✅ drop `emit`
// ✅ `_`-prefix ONLY when a LATER param is used (can't drop) or a contract fixes arity:
arr.map((_item, index) => index);           // _item kept because index is used

In .vue, vue-tsc/eslint-vue already account for <template> usage, so a flagged script var/function is genuinely dead — safe to remove.

3. Real-bug rules (Bucket 1 — fix each by hand)

ts
// no-unsafe-optional-chaining — runtime throw
const n = obj?.list.length;        // ❌ obj?.list can be undefined, .length throws
const n = obj?.list?.length ?? 0;  // ✅

// no-self-assign
this.x = this.x;                   // ❌ dead / typo — did you mean another field?

// no-unreachable
return x; doStuff();               // ❌ doStuff() never runs — remove or reorder

// no-case-declarations — lexical decl leaks across cases
switch (k) { case 1: const a = 1; … }         // ❌
switch (k) { case 1: { const a = 1; … } }      // ✅ block-scope the case

// no-redeclare — merge or rename the duplicate declaration
// no-import-assign — never reassign an imported binding; copy to a local
html
<!-- vue/no-mutating-props — never mutate a prop -->
<!-- ❌ --> <input @input="modelValue = $event" />
<!-- ✅ emit and let the parent own state -->
<input @input="$emit('update:modelValue', $event.target.value)" />

<!-- vue/require-v-for-key -->
<!-- ❌ --> <li v-for="item in items">{{ item }}</li>
<!-- ✅ --> <li v-for="item in items" :key="item.id">{{ item }}</li>

<!-- vue/no-use-v-if-with-v-for — don't combine on one element -->
<!-- ❌ --> <li v-for="i in items" v-if="i.active" />
<!-- ✅ filter in a computed, or wrap v-if on a <template> -->
ts
// vue/no-ref-as-operand — forgot .value
const count = ref(0);
if (count > 5) {}        // ❌ compares the ref object
if (count.value > 5) {}  // ✅

// vue/return-in-computed-property / vue/no-side-effects-in-computed-properties
const total = computed(() => { items.push(x); });  // ❌ side effect + no return
const total = computed(() => items.reduce((a, b) => a + b, 0)); // ✅ pure + returns
3.1 More Vue rules (also in the backlog)
html
<!-- vue/no-unused-components (81) — component imported/registered but never used
     in the template. Remove the import (script setup) or the components:{} entry. -->

<!-- vue/no-unused-vars (10) — a template-scoped var (v-for / v-slot) is never used -->
<!-- ❌ --> <li v-for="(item, i) in items">{{ item }}</li>   <!-- i unused -->
<!-- ✅ --> <li v-for="item in items">{{ item }}</li>        <!-- drop it -->

<!-- vue/require-v-for-key already in §3; vue/valid-v-for (1) — v-for must have valid
     syntax + a key on a real element (not on <template> without key on children) -->

<!-- vue/valid-attribute-name (1) — attribute name has illegal chars (e.g. a stray
     space/quote in a :prop name) → fix the attribute name -->

<!-- vue/no-parsing-error (2) — malformed template (unclosed tag, bad directive
     expression, duplicate attribute) → fix the markup; the message pinpoints it -->

<!-- vue/require-toggle-inside-transition (1) — <transition> needs a v-if/v-show/
     :key/dynamic-component child to actually transition -->
<!-- ✅ --> <transition><div v-if="open" /></transition>

<!-- vue/no-reserved-component-names (1) — don't name a component after an HTML/SVG
     element (e.g. `Button`, `Image`) → rename (e.g. `AppButton`) -->
ts
// vue/no-dupe-keys (12) — the same key appears in two option groups
// (props + data/computed/methods), so one silently shadows the other.
props: { value: {} }, data: () => ({ value: 1 })   // ❌ rename one

// vue/require-valid-default-prop (5) — object/array prop defaults MUST be a factory
props: { items: { type: Array, default: [] } }              // ❌ shared ref
props: { items: { type: Array, default: () => [] } }        // ✅ factory

// vue/prefer-import-from-vue (1) — import Vue APIs from "vue", not "@vue/*"
import { ref } from "@vue/runtime-core";   // ❌
import { ref } from "vue";                 // ✅

// vue/valid-next-tick (1) — await nextTick() OR pass a callback; don't do both,
// and don't call it without using the result.
await nextTick();                          // ✅

4. Low-risk / mechanical (Bucket 2)

ts
// no-prototype-builtins
if (obj.hasOwnProperty(k)) {}                              // ❌
if (Object.prototype.hasOwnProperty.call(obj, k)) {}      // ✅

// no-useless-escape — drop the needless backslash (prettier/--fix often handles it)
/\-/  →  /-/

// no-empty — FIRST ask: does the block do anything? If it does NOTHING,
// DELETE it — do not comment an empty block into existence.
if (a) { doX(); } else { }            // ❌ empty else that does nothing
if (a) { doX(); }                     // ✅ drop the dead branch entirely
// Only keep an empty block when it MUST exist (a catch that deliberately
// swallows, a required override) — then add a reason comment:
catch (e) {}                          // ❌
catch (e) { /* ignore: best-effort */ } // ✅ intentional no-op

// no-useless-catch — a catch that only rethrows adds nothing → remove the try/catch
// no-async-promise-executor — never pass an async fn to new Promise; hoist the body
new Promise(async (res) => { … });    // ❌
Show full SKILL.md (609 more words)Show less

5. Why some rules stay OFF (don't "fix" these)

  • no-undef — OFF permanently. TypeScript already checks undefined symbols; the rule can't see Vue macros / auto-imports / type-only refs (thousands of false positives).
  • core no-unused-vars — OFF, superseded by the @typescript-eslint version.
  • prettier/prettier, vue/max-attributes-per-line, vue/multi-word-component-names — formatting/opinion; owned by the formatter or a team decision, not this gate.

6. TypeScript compiler errors (type-check:app)

Enabled compiler flags (tsconfig.app.json): strict: true + noImplicitReturns: true. The gate is a hard 0.

ts
// TS7030 noImplicitReturns — make the IMPLICIT fall-off `undefined` explicit (pure no-op).
// The added return must equal today's runtime value — never invent a value, never add `break`.
function f(x: number) { if (x > 0) return "a"; }          // ❌
function f(x: number) { if (x > 0) return "a"; return undefined; } // ✅
// If a declared return type forbids undefined but a path legitimately falls off,
// widen it at the DECLARATION site (`: string` → `: string | undefined`) — not a cast.

noFallthroughCasesInSwitch is intentionally OFF. Unlike ESLint's no-fallthrough, the TS flag has no // falls through comment escape hatch, so it cannot express deliberate cascades (e.g. the cumulative dashboard schema-version migrations in convertDashboardSchemaVersion.ts) without a behavior-risky refactor. ESLint's comment-aware no-fallthrough already guards new code — keep intentional fallthrough marked // falls through. (A version-bumping if-chain is the only behavior-preserving way to satisfy the TS flag; don't retrofit it onto existing migration switches.)

Cast anti-patterns → declaration-site
ts
// ❌ cast at the use site
const t = ref(props.tab);            // Ref<string>
<Editor :lang="(t as 'sql'|'promql')" />

// ✅ type the source (prop + ref)
tab: { type: String as PropType<'sql'|'promql'|'custom'> }
const t = ref(props.tab);            // Ref<'sql'|'promql'|'custom'>
<Editor :lang="t" />

// ❌ (x as unknown as string) coercing an array key
colOrder[selectedStream as unknown as string]
// ✅ express the real operation
colOrder[selectedStream.join(",")]

Casts that are legitimately kept: Array as PropType<T> (required Vue syntax), as const, as unknown as X at a genuine external boundary (reka-ui/DOM/JSON.parse/ 3rd-party), and a narrowing assertion for a runtime invariant the compiler can't prove (document it). Deriving an API type from the backend Rust struct beats any cast.

7. Formatting (Prettier)

Prettier is installed but not yet enabled (prettier/prettier is off, no repo config). When adopted, the intended standard is printWidth 80, semi, double quotes, trailingComma all, tabWidth 2 (the codebase already targets 80). It's a one-shot repo-wide reformat (~2,100 files) + a format script, done as its own commit — not something to hand-apply per file. Once enabled, Prettier owns whitespace/quotes/commas; ESLint owns correctness.

8. Workflow

  1. npm run type-check:app → fix type errors first (types unblock lint clarity).
  2. npm run lint:ci -- --quiet → must be 0 errors (warnings are the ratchet backlog, allowed).
  3. For a bucket rollout: fix all of a rule's violations, then flip it warn → error (§9).
  4. The type-check gate is a hard 0 (any error TS fails); any ESLint error fails lint:ci. Warnings are the ratchet backlog — don't add new ones.

9. Gradual rollout — flipping a rule warn → error

The config keeps the backlog as warn so CI never blocks. To enforce a rule permanently, drive its count to zero, then flip it. Never flip a rule that still has violations (that turns the whole lint:ci gate red on every PR), and never flip everything at once (2,700+ errors). One rule (or one small bucket) per PR.

Per-rule procedure

  1. Count a rule's violations:
    bash
    npx eslint "src/**/*.{js,ts,vue}" --rule '{"<rule-id>":"error"}' -f unix 2>/dev/null \
      | grep -c "<rule-id>"
  2. Fix every one using its section above (§2–§6).
  3. Re-run → the rule reports 0.
  4. In eslint.config.js, change that rule from "warn" to "error".
  5. npm run lint:ci must exit 0. Commit.

Regenerate the live backlog any time

bash
npx eslint "src/**/*.{js,ts,vue}" -f json 2>/dev/null | node -e '
const d=JSON.parse(require("fs").readFileSync(0,"utf8"));const by={};
for(const f of d)for(const m of f.messages)if(m.severity===1)by[m.ruleId]=(by[m.ruleId]||0)+1;
for(const[r,c]of Object.entries(by).sort((a,b)=>b[1]-a[1]))console.log(String(c).padStart(5),r);'

Recommended order (ascending effort; counts are a snapshot — regenerate for live numbers):

#BucketRules (see section)~countHow
—Done4 zero-violation rules already at error (no-shadow-restricted-names, vue/valid-v-else-if, vue/no-deprecated-v-bind-sync, vue/no-v-text-v-html-on-component)0already enforced
1Real bugs (§3, §3.1)no-unreachable, no-self-assign, no-redeclare, no-case-declarations, no-unsafe-optional-chaining, no-import-assign, vue/no-dupe-keys, vue/no-ref-as-operand, vue/return-in-computed-property, vue/no-side-effects-in-computed-properties, vue/require-valid-default-prop, vue/require-v-for-key, vue/no-use-v-if-with-v-for, vue/valid-*, vue/no-parsing-error, vue/no-reserved-component-names, vue/require-toggle-inside-transition~90fix by hand → flip each to error
2Mechanical (§4)no-prototype-builtins (128), no-useless-escape (78), no-useless-catch (29), no-async-promise-executor (17), no-empty (16)~270mostly trivial
3Vue correctness (§3, §3.1)vue/no-mutating-props (228), vue/no-unused-components (81), vue/no-unused-vars (10)~320real refactors; ratchet down
4Unused code (§2)@typescript-eslint/no-unused-vars (2,072)~2,072eslint-plugin-unused-imports autofix + _-prefix; ratchet, not one PR

TypeScript flags (separate track, tsconfig.app.json, §6): noImplicitReturns (60) → noFallthroughCasesInSwitch (8; migration-switch refactor first) → noUnusedLocals/ noUnusedParameters only if TS (not ESLint) owns unused. noUncheckedIndexedAccess is a no‑op until strictNullChecks (its own future initiative).

Full rationale, research, and per-bucket detail live in the lint & type-check strictness rollout design doc.

© openobserve, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .claude/skills/eslint-error-handling of openobserve/openobserve.

Open the folder on GitHubat commit 0e9ab49

Compare with similar skills

OpenObserve ESLint and TypeScript Fixes next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

OpenObserve ESLint and TypeScript Fixes compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
OpenObserve ESLint and TypeScript Fixes this skillopenobserve/openobserve22k—~5.1kAutomated safety check: PassAGPL-3.0
Code Qualityredis/RedisInsight8.9k—~1.2kAutomated safety check: PassCustom licence
Obsidian Plugin Development Guidelinesgapmiss/obsidian-plugin-skill190—~4.5kAutomated safety check: PassMIT
Cb Code QualityBlkLeg/CircuitBreaker201—~1.9kAutomated safety check: PassMIT
Fallow Setupfallow-rs/fallow-skills129—~1.1kAutomated safety check: PassMIT
Ban Type AssertionsFactory-AI/factory-plugins111—~1.7kAutomated safety check: PassNone

Similar skills

  • Code Quality

    redis/RedisInsight

    Official

    Code-quality standards for RedisInsight: TypeScript strictness, naming conventions (camelCase, PascalCase, UPPERSNAKECASE), linting rules, no any without reason, no !important in styles, and…

    8.9k GitHub stars~1.2k tokensUpdated 4 days ago
    DevelopmentAuto-check passed
  • Obsidian Plugin Development Guidelines

    gapmiss/obsidian-plugin-skill

    Rules and references for building Obsidian plugins: ESLint rules, TypeScript practices, memory cleanup, API choices, UI standards and the community submission process.

    190 GitHub stars~4.5k tokensUpdated 15 days ago
    DevelopmentAuto-check passed
  • Cb Code Quality

    BlkLeg/CircuitBreaker

    Circuit Breaker code conventions and the quality gates that actually block a push — ruff, mypy, eslint, the pytest coverage ratchet, and the make verify tiers.

    201 GitHub stars~1.9k tokensUpdated 4 days ago
    DevelopmentAuto-check passed
  • Fallow Setup

    fallow-rs/fallow-skills

    Set up or modernize code-quality tooling for JavaScript and TypeScript projects.

    129 GitHub stars~1.1k tokensUpdated today
    DevelopmentAuto-check passed
  • Ban Type Assertions

    Factory-AI/factory-plugins

    Ban as type assertions in a package via the @typescript-eslint/consistent-type-assertions lint rule, replacing them with compiler-verified type-safe alternatives.

    111 GitHub stars~1.7k tokensUpdated 2 days ago
    DevelopmentAuto-check passed
  • Migrate or upgrade TypeScript tooling in the Phoenix monorepo.

    12k GitHub stars~2.8k tokensUpdated today
    DevelopmentAuto-check passed

More from openobserve/openobserve

  • O2 Review Loop

    openobserve/openobserve

    Splits a change into planner, coder and independent reviewer roles: you confirm a spec, a subagent implements it, and a separate reviewer checks each round's local WIP commit.

    22k GitHub stars~3.7k tokensUpdated today
    Auto-check passed
  • OpenObserve PR Brief

    openobserve/openobserve

    Produces a read-only morning brief of your open pull requests across the openobserve GitHub org, with a next step for each and a reminder for idle ones.

    22k GitHub stars~1.8k tokensUpdated today
    Auto-check passed

Questions about OpenObserve ESLint and TypeScript Fixes

What does OpenObserve ESLint and TypeScript Fixes do?

A playbook for fixing ESLint and TypeScript errors in the OpenObserve web frontend, with rule-by-rule guidance and typing conventions. The stack is Vue 3, TypeScript, an ESLint flat config and Prettier, and the gates are npm run lint:ci and npm run type-check:app (vue-tsc), both of which must stay at 0 errors. Six golden rules apply to every fix: never use any, prefer types at the declaration site over as casts, keep type-only fixes from changing runtime behavior, use strict equality only, keep comments to one or two lines, and fix rather than suppress, with eslint-disable or @ts-expect-error reserved for genuine false positives and given a reason.

When should I use OpenObserve ESLint and TypeScript Fixes?

OpenObserve ESLint and TypeScript Fixes fits situations like: fixing lint or type-check errors in the OpenObserve web frontend; deciding whether a new type belongs inline or in a shared file; replacing any and as casts with proper types; writing new Vue code that already meets the repo's lint standard.

How do I install OpenObserve ESLint and TypeScript Fixes in Claude Code?

Run `npx skills add openobserve/openobserve --skill eslint-error-handling -a claude-code`. Or copy the skill folder (.claude/skills/eslint-error-handling in openobserve/openobserve) into .claude/skills/eslint-error-handling in your project. Claude Code loads it when a task matches its description.

How do I install OpenObserve ESLint and TypeScript Fixes in Codex?

Run `npx skills add openobserve/openobserve --skill eslint-error-handling -a codex`. Or copy the skill folder (.claude/skills/eslint-error-handling in openobserve/openobserve) into .agents/skills/eslint-error-handling in your project. Codex loads it when a task matches its description.

Can I use OpenObserve ESLint and TypeScript Fixes in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add openobserve/openobserve --skill eslint-error-handling -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/eslint-error-handling, .gemini/skills/eslint-error-handling, .github/skills/eslint-error-handling and .opencode/skills/eslint-error-handling in your project.

What does OpenObserve ESLint and TypeScript Fixes need to run?

Going by SKILL.md and its folder, OpenObserve ESLint and TypeScript Fixes needs the command-line tools its instructions call (npm, npx and node). Our summary lists: Node.js with the web/ project dependencies installed.

Does OpenObserve ESLint and TypeScript Fixes access the network?

SKILL.md contains no URLs. Its commands use npm and npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is OpenObserve ESLint and TypeScript Fixes safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does OpenObserve ESLint and TypeScript Fixes use?

OpenObserve ESLint and TypeScript Fixes is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does OpenObserve ESLint and TypeScript Fixes use?

About 5.1k tokens (SKILL.md is roughly 20k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to OpenObserve ESLint and TypeScript Fixes?

Skills that share tags, products or a category with OpenObserve ESLint and TypeScript Fixes: Code Quality (redis/RedisInsight, 8.9k stars), Obsidian Plugin Development Guidelines (gapmiss/obsidian-plugin-skill, 190 stars), Cb Code Quality (BlkLeg/CircuitBreaker, 201 stars) and Fallow Setup (fallow-rs/fallow-skills, 129 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains OpenObserve ESLint and TypeScript Fixes?

openobserve (a GitHub organization) maintains it in openobserve/openobserve, which has 22,306 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on October 9, 2026.

Source: openobserve/openobserve on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.