Agent skill

Opik Backend Patterns

by comet-ml in comet-ml/opik

Java conventions for the Opik backend: layered resource, service and DAO classes, naming rules, Lombok and Guice usage, and notes on MySQL, ClickHouse, migrations and testing.

Apache-2.0Auto-check passedBackend & APIs

Install Opik Backend Patterns

skills CLI
$ npx skills add comet-ml/opik --skill opik-backend -a claude-code

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

GitHub CLI
$ gh skill install comet-ml/opik opik-backend --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/comet-ml/opik.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/opik-backend .claude/skills/opik-backend && 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
opik-backend
GitHub stars
22k
Token cost
~2.4k tokens
SKILL.md length
549 words
Files
6
Skills in repo
19
Repo updated
First seen
Licence
Apache-2.0

At a glance

Java conventions for the Opik backend: layered resource, service and DAO classes, naming rules, Lombok and Guice usage, and notes on MySQL, ClickHouse, migrations and testing.

  • Adding a REST resource, service or DAO to apps/opik-backend
  • SKILL.md covers Architecture, Naming Conventions, Lombok Conventions and Critical Gotchas, plus 4 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • Writing ClickHouse or MySQL queries and migrations for Opik

What it does

The architecture is layered, from Resource to Service to DAO, never skipping a layer, with Guice dependency injection through constructors. MySQL holds metadata and transactional data, while ClickHouse holds append-only analytics. Naming is split: resources, resource tests, URL paths and database tables are plural (TracesResource, /v1/private/traces, traces), while DAO and service classes are singular (TraceDAO, TraceService).

Lombok rules say to annotate records and DTOs with @Builder(toBuilder = true) and construct them through builders. Internal records use Lombok @NonNull on required fields, whereas request-body DTOs validated with Jakarta annotations should not stack @NonNull on top. Injection uses @RequiredArgsConstructor(onConstructor_ = @Inject), and validation annotations stay off interface parameters. A gotchas section covers a StringTemplate memory leak, and companion files cover ClickHouse, migrations, MySQL, permissions and testing.

When your agent uses it

  • Adding a REST resource, service or DAO to apps/opik-backend
  • Writing ClickHouse or MySQL queries and migrations for Opik
  • Naming new classes, URL paths and tables consistently
  • Setting up Lombok annotations on new records and DTOs

Example prompts

  • “Add a new datasets endpoint to the Opik backend following the Resource, Service and DAO layers.”
  • “Write the ClickHouse migration and DAO for a new feedback_scores table.”
  • “Review my new TraceService for the Lombok and injection conventions.”

Requirements

  • The Opik repository, specifically apps/opik-backend
  • MySQL and ClickHouse for running the backend

What it can do on your machine

Read from SKILL.md and the folder at commit 2982cd7. 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

    No scripts in the folder and no shell commands in SKILL.md (its code samples are java).

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

  • Network

    No URLs in SKILL.md.

    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

Opik Backend Patterns loads about 2.4k tokens when it runs. Until then it costs about 33 tokens; SKILL.md has 549 words of instructions outside code blocks.

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

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 comet-ml/opik at commit 2982cd7, republished under its Apache-2.0 licence (© comet-ml). 549 words, ~2,418 tokens.

Download SKILL.mdSave it as .claude/skills/opik-backend/SKILL.md (or your agent's skills folder). This skill also uses 5 other files; get the full folder from GitHub.
name
opik-backend
description
Java backend patterns for Opik. Use when working in apps/opik-backend, designing APIs, database operations, or services.

Opik Backend

Architecture

  • Layered: Resource → Service → DAO (never skip layers)
  • DI: Guice modules, constructor injection with @Inject
  • Databases: MySQL (metadata, transactional) + ClickHouse (analytics, append-only)

Naming Conventions

Plural Names (Resources, Tests, URLs, DB Tables)
  • Resource classes: TracesResource, SpansResource, DatasetsResource (not TraceResource)
  • Resource test classes: TracesResourceTest, SpansResourceTest, DatasetsResourceTest (not TraceResourceTest)
  • URL paths: /v1/private/traces, /v1/private/spans (not /v1/private/trace)
  • DB table names: traces, spans, feedback_scores (not trace, span, feedback_score)
Singular Names (DAO, Service)
  • DAO classes: TraceDAO, SpanDAO, DatasetDAO (not TracesDAO)
  • Service classes: TraceService, SpanService, DatasetService (not TracesService)
java
// ✅ GOOD
@Path("/v1/private/traces")
public class TracesResource { }

// ✅ GOOD - DAO and Service use singular
public class TraceDAO { }
public class TraceService { }

// ✅ GOOD - test classes match plural resource name
public class TracesResourceTest { }

// ❌ BAD - singular test class
public class TraceResourceTest { }

// ❌ BAD - singular resource/URL
@Path("/v1/private/trace")
public class TraceResource { }

// ❌ BAD - plural DAO/Service
public class TracesDAO { }
public class TracesService { }

Lombok Conventions

Records and DTOs
  • Always annotate records/DTOs with @Builder(toBuilder = true)
  • Use builders (not constructors) when instantiating records
  • For internal records (built programmatically, never validated by Bean Validation), use Lombok @NonNull on required fields — it generates a runtime null check at construction
  • For request-body DTOs validated via @Valid cascade (Jakarta validators like @NotNull/@NotBlank/@Size), use Jakarta annotations only — do not stack @NonNull on top. Bean Validation already enforces the contract at the API boundary; doubling up is redundant noise
java
// ✅ GOOD - internal record, Lombok @NonNull
@Builder(toBuilder = true)
record MyData(@NonNull UUID id, @NonNull String name, String description) {}

MyData data = MyData.builder()
        .id(id)
        .name(name)
        .build();

// ✅ GOOD - request-body DTO, Jakarta validators only
@Builder(toBuilder = true)
public record MyRequest(
        @NotNull UUID id,
        @NotBlank String name,
        @NotNull @Size(min = 1, max = 1000) @Valid List<MyItem> items) {}

// ❌ BAD - plain constructor (positional mistakes, less readable)
new MyData(id, name, null);

// ❌ BAD - @Builder without toBuilder
@Builder
record MyData(UUID id, String name) {}

// ❌ BAD - stacking @NonNull and @NotNull on the same field
public record MyRequest(@NonNull @NotNull UUID id) {}
Dependency Injection
  • Use @RequiredArgsConstructor(onConstructor_ = @Inject) instead of manual constructors
java
// ✅ GOOD
@RequiredArgsConstructor(onConstructor_ = @Inject)
public class MyService {
    private final @NonNull DependencyA depA;
    private final @NonNull DependencyB depB;
}

// ❌ BAD - boilerplate constructor
public class MyService {
    private final DependencyA depA;
    @Inject
    public MyService(DependencyA depA) {
        this.depA = depA;
    }
}
Interfaces
  • Don't put validation annotations (@NonNull) on interface method parameters
  • Keep interfaces free of implementation details
java
// ✅ GOOD
interface MyService {
    void process(String workspaceId, UUID promptId);
}

// ❌ BAD - validation on interface
interface MyService {
    void process(@NonNull String workspaceId, @NonNull UUID promptId);
}

Critical Gotchas

StringTemplate Memory Leak
java
// ✅ GOOD
var template = TemplateUtils.newST(QUERY);

// ❌ BAD - causes memory leak via STGroup singleton
var template = new ST(QUERY);
List Access
java
// ✅ GOOD
users.getFirst()
users.getLast()

// ❌ BAD
users.get(0)
users.get(users.size() - 1)
SQL Query Construction

Never build a query out of Java string operations. No +, no String.format / .formatted(...), no StringBuilder, no MessageFormat, no String.join over clauses. A query is declared once as a text block, and everything that varies goes through exactly one of two mechanisms:

What variesMechanism
A value — id, name, timestamp, list of ids:placeholder + .bind("placeholder", value)
A fragment — predicate, sort clause, projected column, CTEStringTemplate <if(x)>…<endif>, <else>, <x> + template.add("x", …)

Why: interpolating values is the SQL-injection surface, and interpolating fragments hides which query a DAO actually runs — the declaration site stops being readable, and callers drift apart over time.

java
// ✅ GOOD - text block, values bound, structure via StringTemplate
@SqlQuery("""
        SELECT * FROM datasets
        WHERE workspace_id = :workspace_id
        <if(name)> AND name like concat('%', :name, '%') <endif>
        """)

// ❌ BAD - string concatenation
@SqlQuery("SELECT * FROM datasets " +
        "WHERE workspace_id = :workspace_id " +
        "<if(name)> AND name like concat('%', :name, '%') <endif> ")

A predicate that differs between callers is a fragment, so it belongs in the template — not in a %s slot the caller fills in:

java
// ❌ BAD - caller splices the predicate in
private static final String TOKEN_USAGE_NAMES_TEMPLATE = """
        SELECT DISTINCT name FROM (
            SELECT usage FROM spans FINAL
            WHERE workspace_id = :workspace_id
            AND %s
        ) ...
        """;

static String tokenUsageNames(String projectPredicate) {
    return TOKEN_USAGE_NAMES_TEMPLATE.formatted(projectPredicate);
}

// caller: tokenUsageNames("project_id IN :project_ids")

// ✅ GOOD - both shapes live in the template, the caller picks one
private static final String TOKEN_USAGE_NAMES = """
        SELECT DISTINCT name FROM (
            SELECT usage FROM spans FINAL
            WHERE workspace_id = :workspace_id
            <if(project_ids)> AND project_id IN :project_ids <endif>
            <if(project_id)> AND project_id = :project_id <endif>
        ) ...
        """;

var template = TemplateUtils.newST(TOKEN_USAGE_NAMES);
template.add("project_ids", true);
...
statement.bind("project_ids", projectIds.toArray(new UUID[0]));

A fragment that genuinely can't be enumerated in the template — a user-chosen sort field or filter clause — must be produced by the allow-listed builders (SortingQueryBuilder, FilterQueryBuilder), never assembled from raw request strings.

.formatted(...) stays correct for log and exception messages. The rule is about SQL text only.

Some %s query templates predate this rule. Don't copy them and don't add new ones.

Show full SKILL.md (171 more words)Show less
Immutable Collections
java
// ✅ GOOD
Set.of("A", "B", "C")
List.of(1, 2, 3)
Map.of("key", "value")

// ❌ BAD
Arrays.asList("A", "B", "C")

API Design

  • Query parameters that accept lists: Use plural names from the start (e.g., exclude_category_names not exclude_category_name). Starting with a singular name and later adding a plural variant results in two redundant query params on the same endpoint. Plural names are backward-compatible since they work for both single and multiple values.

Error Handling

Use Jakarta Exceptions
java
throw new BadRequestException("Invalid input");
throw new NotFoundException("User not found: '%s'".formatted(id));
throw new ConflictException("Already exists");
throw new InternalServerErrorException("System error", cause);
Error Response Classes
  • Simple: io.dropwizard.jersey.errors.ErrorMessage
  • Complex: com.comet.opik.api.error.ErrorMessage
  • Never create new error message classes

Logging

Format Convention
java
// ✅ GOOD - values in single quotes
log.info("Created user: '{}'", userId);
log.error("Failed for workspace: '{}'", workspaceId, exception);

// ❌ BAD - no quotes
log.info("Created user: {}", userId);
Value Placement

Put the message first and the interpolated values at the end of the sentence, as a trailing name '{}' list. This keeps a stable literal prefix that stays greppable during a production debugging session — a message whose values are interleaved has no fixed substring to search for.

Applies to log.* format strings and to exception messages built with .formatted(...).

java
// ✅ GOOD - literal prefix first, values trailing
log.warn("Alert name is required, workspaceId '{}'", workspaceId);
log.debug("Webhook delivery failed, id '{}', status '{}'", eventId, status);
throw new DestinationGuardException("destination has no valid host, url '%s'".formatted(url));

// ❌ BAD - values interleaved, no greppable prefix
log.debug("Webhook '{}' failed with status '{}'", eventId, status);
throw new DestinationGuardException("destination '%s' has no valid host".formatted(url));
Never Log
  • Emails, passwords, tokens, API keys
  • PII, personal identifiers
  • Database credentials

Reference Files

© comet-ml, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 5 other files in .agents/skills/opik-backend of comet-ml/opik.

  • SKILL.md
  • clickhouse.md
  • migrations.md
  • mysql.md
  • permissions.md
  • testing.md

Open the folder on GitHubat commit 2982cd7

Compare with similar skills

Opik Backend Patterns 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.

Opik Backend Patterns compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Opik Backend Patterns this skillcomet-ml/opik22k—~2.4kAutomated safety check: PassApache-2.0
Flycms Devsunkaifei/FlyCms656—~827Automated safety check: PassMIT
Backend Dev Guidelineslitefuse/litefuse1001 repos~5.8kAutomated safety check: PassCustom licence
Springboot Init Skilljiushiwon/wg-skills114—~2.2kAutomated safety check: NotesApache-2.0
Dr Jskilljdubois/dr-jskill342—~4.6kAutomated safety check: NotesApache-2.0
Progensivaprasadreddy/sivalabs-agent-skills188—~2.7kAutomated safety check: NotesMIT

Similar skills

  • Flycms Dev

    sunkaifei/FlyCms

    FlyCms 项目(backend/ Spring Boot 4.1.1 + frontend/ vue-vben-admin v5)的架构地图与开发规范总纲。凡在本仓库做任何开发——写后端接口、新增/修改模块、管理页面、数据库变更、修 bug、重构——都要先加载本 skill 再动手,即使用户只说"改一下""加个功能";前端登录/菜单/权限专项另见…

    656 GitHub stars~827 tokensUpdated today
    Backend & APIsAuto-check passed
  • Backend Dev Guidelines

    litefuse/litefuse

    Comprehensive backend development guide for Litefuse's Next.js 14/tRPC/Express/TypeScript monorepo.

    100 GitHub starsUsed in 1 repo~5.8k tokens
    Backend & APIsAuto-check passed
  • Springboot Init Skill

    jiushiwon/wg-skills

    Spring Boot 项目一键初始化技能。面向零基础小白,提供环境探测、自动安装、完整 Web 骨架生成、SSE 流式框架、JWT 鉴权、统一响应封装、文件上传接口、一键启动/重启脚本、Swagger 文档,内置 MySQL(默认)/ PostgreSQL / MongoDB 数据库选择。用户只需说"帮我搭一个 Spring Boot…

    114 GitHub stars~2.2k tokensUpdated 2 days ago
    Backend & APIsAuto-check: notes
  • Dr Jskill

    jdubois/dr-jskill

    Creates Java + Spring Boot projects: Web applications, full-stack apps with Vue.js or Angular or React or vanilla JS, PostgreSQL, REST APIs, and Docker.

    342 GitHub stars~4.6k tokensUpdated 9 days ago
    Backend & APIsAuto-check: notes
  • Progen

    sivaprasadreddy/sivalabs-agent-skills

    A skill your agent uses when the user wants to create/generate/scaffold a new Spring Boot project (Maven or Gradle, REST API / Web App / Spring Boot + Angular full stack).

    188 GitHub stars~2.7k tokensUpdated 4 days ago
    Backend & APIsAuto-check: notes
  • Spring Boot Crud Patterns

    giuseppe-trisciuoglio/developer-kit

    Provides and generates complete CRUD workflows for Spring Boot 3 services.

    356 GitHub stars~2.5k tokensUpdated 29 days ago
    Backend & APIsAuto-check: notes

More from comet-ml/opik

All 19 skills in this repo
  • Checklist for wiring a new linter into Opik's Code Quality pipeline: the four files to edit, the silent-failure gotchas and the pass/fail verification loop.

    22k GitHub stars~2.3k tokensUpdated today
    Auto-check passed
  • Shows how to add product analytics events to Opik's frontend, Java backend and Python SDK, all reporting through Segment to PostHog with an opik_ name prefix.

    22k GitHub stars~4.4k tokensUpdated today
    Auto-check passed
  • Investigates a failed Opik end-to-end test from CI, TestOps or a local run, decides regression versus flake, and proposes a fix without editing tests.

    22k GitHub stars~1.8k tokensUpdated today
    Auto-check passed
  • Rules for writing PR descriptions, changelog entries and feature documentation in the Opik repository, including the exact headings that CI requires.

    22k GitHub stars~1.3k tokensUpdated today
    Auto-check passed
  • Turns a code change into one committed, passing Playwright end-to-end spec by resolving the change scope and handing authoring to a companion skill.

    22k GitHub stars~3.4k tokensUpdated today
    Auto-check passed
  • Starts, rebuilds, and troubleshoots the Opik local dev stack, including an optional Comet Platform integration mode for the Opik team.

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

Questions about Opik Backend Patterns

What does Opik Backend Patterns do?

Java conventions for the Opik backend: layered resource, service and DAO classes, naming rules, Lombok and Guice usage, and notes on MySQL, ClickHouse, migrations and testing. The architecture is layered, from Resource to Service to DAO, never skipping a layer, with Guice dependency injection through constructors. MySQL holds metadata and transactional data, while ClickHouse holds append-only analytics.

When should I use Opik Backend Patterns?

Opik Backend Patterns fits situations like: adding a REST resource, service or DAO to apps/opik-backend; writing ClickHouse or MySQL queries and migrations for Opik; naming new classes, URL paths and tables consistently; setting up Lombok annotations on new records and DTOs.

How do I install Opik Backend Patterns in Claude Code?

Run `npx skills add comet-ml/opik --skill opik-backend -a claude-code`. Or copy the skill folder (.agents/skills/opik-backend in comet-ml/opik) into .claude/skills/opik-backend in your project. Claude Code loads it when a task matches its description.

How do I install Opik Backend Patterns in Codex?

Run `npx skills add comet-ml/opik --skill opik-backend -a codex`. Or copy the skill folder (.agents/skills/opik-backend in comet-ml/opik) into .agents/skills/opik-backend in your project. Codex loads it when a task matches its description.

Can I use Opik Backend Patterns 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 comet-ml/opik --skill opik-backend -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/opik-backend, .gemini/skills/opik-backend, .github/skills/opik-backend and .opencode/skills/opik-backend in your project.

What does Opik Backend Patterns need to run?

SKILL.md names no scripts, command-line tools or credentials: Opik Backend Patterns is instructions for the agent only. Our summary lists: The Opik repository, specifically apps/opik-backend; MySQL and ClickHouse for running the backend.

Does Opik Backend Patterns access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Opik Backend Patterns 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 Opik Backend Patterns use?

Opik Backend Patterns is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Opik Backend Patterns use?

About 2.4k tokens (SKILL.md is roughly 9.7k 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 Opik Backend Patterns?

Skills that share tags, products or a category with Opik Backend Patterns: Flycms Dev (sunkaifei/FlyCms, 656 stars), Backend Dev Guidelines (litefuse/litefuse, 100 stars), Springboot Init Skill (jiushiwon/wg-skills, 114 stars) and Dr Jskill (jdubois/dr-jskill, 342 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Opik Backend Patterns?

comet-ml (a GitHub organization) maintains it in comet-ml/opik, which has 22,468 GitHub stars. The repository holds 19 skills in this directory. The repository was last updated on October 9, 2026.

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