upsert-case

Add a new audio API example case or modify an existing one in the APIExample-Audio Android demo — creates or updates Fragment class, XML layout, string resources, and nav_graph registration. Use when: adding a new Agora audio API demo screen, modifying an existing case's implementation or registration, implementing a new audio feature example in Java + XML layouts, registering a new case via @Example annotation, subclassing BaseFragment for a new audio demo screen, or updating an existing case's strings, layout, or nav entry. This project uses voice-sdk — no video APIs available. Keywords: add case, modify case, update case, new fragment, nav_graph, @Example, BaseFragment, APIExample-Audio, audio case, voice-sdk, new screen, audio demo, upsert case.

342 stars

Best use case

upsert-case is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Add a new audio API example case or modify an existing one in the APIExample-Audio Android demo — creates or updates Fragment class, XML layout, string resources, and nav_graph registration. Use when: adding a new Agora audio API demo screen, modifying an existing case's implementation or registration, implementing a new audio feature example in Java + XML layouts, registering a new case via @Example annotation, subclassing BaseFragment for a new audio demo screen, or updating an existing case's strings, layout, or nav entry. This project uses voice-sdk — no video APIs available. Keywords: add case, modify case, update case, new fragment, nav_graph, @Example, BaseFragment, APIExample-Audio, audio case, voice-sdk, new screen, audio demo, upsert case.

Teams using upsert-case should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/upsert-case/SKILL.md --create-dirs "https://raw.githubusercontent.com/AgoraIO/API-Examples/main/Android/APIExample-Audio/.agent/skills/upsert-case/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/upsert-case/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How upsert-case Compares

Feature / Agentupsert-caseStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Add a new audio API example case or modify an existing one in the APIExample-Audio Android demo — creates or updates Fragment class, XML layout, string resources, and nav_graph registration. Use when: adding a new Agora audio API demo screen, modifying an existing case's implementation or registration, implementing a new audio feature example in Java + XML layouts, registering a new case via @Example annotation, subclassing BaseFragment for a new audio demo screen, or updating an existing case's strings, layout, or nav entry. This project uses voice-sdk — no video APIs available. Keywords: add case, modify case, update case, new fragment, nav_graph, @Example, BaseFragment, APIExample-Audio, audio case, voice-sdk, new screen, audio demo, upsert case.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Upsert Case — APIExample-Audio

## Adding a New Case

Touch exactly 4 files (all paths relative to `app/src/main/`):

| File | What to add |
|---|---|
| `java/.../examples/{basic\|advanced\|audio}/YourCaseName.java` | Fragment class |
| `res/layout/fragment_your_case_name.xml` | XML layout |
| `res/values/strings.xml` | 2 strings |
| `res/navigation/nav_graph.xml` | 1 action + 1 destination |

Registration is automatic via reflection — no other files needed.

**voice-sdk constraint**: Do NOT call `enableVideo()`, `setupLocalVideo()`, `VideoCanvas`, or any video API — the module does not exist and will crash at runtime.

---

### Step 1: Clarify before coding

Before writing a single line, ask:
- **What audio API am I demonstrating?** — determines which existing case is the closest reference to copy patterns from
- **BASIC or ADVANCED group?** — BASIC for fundamental join/leave audio patterns; ADVANCED for feature-specific audio APIs
- **What's the sort index?** — index must be unique within the group. BASIC uses 0–9, ADVANCED starts from 10. Run `query-cases` skill first; a collision causes silent ordering bugs at runtime
- **Any special permissions beyond `RECORD_AUDIO`?** — most audio cases only need `RECORD_AUDIO`; check if the API requires anything else

---

### Step 2: Create the Fragment

**MANDATORY — READ ENTIRE FILE before writing any code**:
[`references/fragment-template.java`](references/fragment-template.java)

Do NOT skip — the `setParameters`, `handler.post`, `getPrivateCloudConfig()` null-check, `AudioSeatManager` wiring, and voice-sdk constraints are only fully shown there and are required in every case.

**Do NOT load** any other reference files for this task.

Non-obvious points the template highlights:

- `setParameters(...)` for app scenario reporting — **required in every case**, do not remove
- `handler.post(RtcEngine::destroy)` — NOT `RtcEngine.destroy()` directly; direct call blocks UI thread (ANR)
- `getPrivateCloudConfig()` null-check before `setLocalAccessPoint()` — returns null on non-private-cloud builds (NPE)
- All `IRtcEngineEventHandler` callbacks run on a **background thread** — always `runOnUIThread()` for UI
- `onActivityCreated` → create engine; `onDestroy` → `leaveChannel()` then `handler.post(RtcEngine::destroy)`
- `ChannelMediaOptions` must NOT set `publishCameraTrack` or `autoSubscribeVideo` — voice-sdk has no video module
- Use `AudioSeatManager` (not `VideoReportLayout`) to visualize remote participants

---

### Step 3: Create the XML layout

Typical audio layout — channel input + join button + audio controls:

```xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <!-- audio status / waveform view goes here -->

    <LinearLayout
        android:id="@+id/ll_join"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <androidx.appcompat.widget.AppCompatEditText
            android:id="@+id/et_channel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:digits="@string/chanel_support_char"
            android:hint="@string/channel_id" />

        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_join"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/join" />
    </LinearLayout>
</RelativeLayout>
```

For waveform visualization, copy the `WaveformView` pattern from `fragment_join_channel_audio.xml`.

---

### Step 4: Add nav entries

File: `res/navigation/nav_graph.xml`

**Action** — inside `<fragment android:id="@+id/Ready">` (NOT mainFragment — mainFragment only has one action, to Ready):

```xml
<action
    android:id="@+id/action_mainFragment_to_yourCaseName"
    app:destination="@id/yourCaseName" />
```

**Destination** — at root `<navigation>` level:

```xml
<fragment
    android:id="@+id/yourCaseName"
    android:name="io.agora.api.example.examples.advanced.YourCaseName"
    android:label="@string/item_your_case_name"
    tools:layout="@layout/fragment_your_case_name" />
```

`action android:id` must exactly match `actionId` in `@Example`.

---

### Step 5: Update ARCHITECTURE.md

Add one line to the case list in `ARCHITECTURE.md` under the correct directory section (`basic/`, `advanced/`, or `audio/`):

```
├── YourCaseName.java    # [index] "Display Name" — key API description
```

Keep the format consistent with existing entries. This file is the fast-lookup index used by `query-cases` — keeping it current avoids full directory scans.

---

## Modifying an Existing Case

When modifying an existing case rather than creating a new one, identify which files need changes based on what you are updating:

| What changed | Files to touch |
|---|---|
| Implementation logic (API calls, event handling) | `java/.../examples/{basic\|advanced\|audio}/CaseName.java` |
| UI layout (views, controls) | `res/layout/fragment_case_name.xml` |
| Display name or tips text | `res/values/strings.xml` |
| Sort index or group (BASIC ↔ ADVANCED) | `@Example` annotation in the Fragment class |
| Navigation label | `res/navigation/nav_graph.xml` (fragment label attribute) |
| Class rename or package move | Fragment class, `nav_graph.xml` (android:name + destination id), `@Example` annotation (actionId), layout file name, `ARCHITECTURE.md` |

After making changes:

1. **Verify `@Example` annotation consistency** — ensure `index`, `group`, `name`, `actionId`, and `tipsId` still match the actual string resources, nav action ID, and intended group/position. A mismatch causes the case to silently disappear from the list or navigate to the wrong screen.
2. **Update `res/values/strings.xml`** if the display name or tips text changed.
3. **Update `res/navigation/nav_graph.xml`** if the class name, package, or label changed.
4. **Update `ARCHITECTURE.md`** — update the Directory Layout entry and the Case Index table row to reflect any changes to the case name, path, Key APIs, or description.

---

## Verify

```bash
./gradlew assembleDebug
```

- [ ] Case appears in correct group at expected sort position
- [ ] Tap navigates to the case screen (silent failure = nav action in wrong fragment)
- [ ] `onJoinChannelSuccess` fires in Logcat
- [ ] After pressing back, check Logcat for `RtcEngine.destroy` within ~2 seconds — if missing, there is a lifecycle bug in `onDestroy`
- [ ] `ARCHITECTURE.md` Case Index table is updated — row added (new case) or row updated (modified case) with correct Case, Path, Key APIs, and Description
- [ ] `@Example` annotation fields (`index`, `group`, `name`, `actionId`, `tipsId`) are consistent with string resources and nav_graph entries

---

## When to Use a Spec Instead

If the case meets any of the following criteria, create a Spec rather than using this skill directly:

1. Involves coordinated calls across two or more Agora API modules
2. Requires a custom UI layout (not one of the standard templates above)
3. Manages multiple channels or multiple engine instances
4. Requires a foreground Service or background thread coordination
5. Involves developing new shared components (widget/utils, etc.)
6. Requires optional module integration (e.g. streamEncrypt)

If none apply → use this skill directly; no Spec needed.

### Spec Requirements Document Must Include

- List of APIs the case demonstrates (audio APIs only)
- User interaction flow description
- Expected RtcEngine lifecycle behavior
- Required permissions (typically only `RECORD_AUDIO`)

### Spec Design Document Must Include

- Target project identifier: `APIExample-Audio`
- Class/file structure design
- API call sequence (Mermaid sequence diagram recommended)
- State management approach
- UI layout plan
- Integration points with existing shared components
- Case registration info: class name, display name, group (BASIC/ADVANCED), sort index — finalize during design to avoid conflicts
- Generate `@Example` annotation parameters, `nav_graph.xml` action + destination, `strings.xml` key names (`item_` prefix)
- Read `ARCHITECTURE.md` or use the `query-cases` skill to check existing indices
- voice-sdk checks: no video APIs (`enableVideo`, `setupLocalVideo`, `setupRemoteVideo`, `VideoCanvas`, `startScreenCapture`) — violations must be eliminated at design time
- Risk identification and mitigation (API availability, permissions, thread safety, performance)

### Spec Task List Integration

- Mark which sub-tasks can be executed with this `upsert-case` skill, and provide skill input parameters
- Mark which sub-tasks require manual coding, and provide target file paths and change summaries
- New shared component creation tasks must come before case implementation tasks

---

## NEVER

- **NEVER** call any video API (`enableVideo`, `setupLocalVideo`, `VideoCanvas`) — voice-sdk has no video module; crash is immediate.
- **NEVER** put the nav action inside `<fragment id="mainFragment">` — it belongs in `<fragment id="Ready">`. mainFragment only routes to Ready; all case actions live in Ready. Wrong placement causes silent navigation failure at runtime.
- **NEVER** call `RtcEngine.destroy()` directly on the main thread — always `handler.post(RtcEngine::destroy)`. Direct call blocks the UI thread and causes ANR.
- **NEVER** call `setLocalAccessPoint()` without null-checking `getPrivateCloudConfig()` first — it returns null on standard builds, causing NPE.
- **NEVER** update UI directly inside `IRtcEngineEventHandler` callbacks — they run on a background thread. Always wrap with `runOnUIThread()`.
- **NEVER** omit `setParameters(...)` — it's required for Agora backend usage reporting in every case; omitting it causes silent reporting failure even though the app appears to work normally.

Related Skills

review-case

342
from AgoraIO/API-Examples

Review an existing case implementation against project-specific red lines and coding standards. Use after implementing or modifying a case. Use when: reviewing a case for correctness, checking red-line compliance, verifying lifecycle and threading patterns, auditing an existing Fragment. Keywords: review, audit, check, red lines, lifecycle, threading, compliance.

query-cases

342
from AgoraIO/API-Examples

Query and browse existing API example cases in the APIExample-Audio Android demo — lists cases by group, finds which case demonstrates a specific Agora audio API, checks sort index availability, and resolves display names from string resources. Use when: someone asks what cases exist, which audio APIs are demonstrated, wants to find a case by name or API (e.g. setVoiceBeautifierPreset, enableSpatialAudio), needs a free sort index before adding a new case, or wants to know if an audio feature is already implemented. This project uses voice-sdk — no video APIs. Keywords: list cases, find case, query cases, @Example, sort index, BASIC, ADVANCED, available cases, existing cases, which case, is there a case, audio case.

join-channel-video-guide

342
from AgoraIO/API-Examples

Guide for implementing video call functionality in business scenarios, including SDK initialization, joining channels, video encoding configuration, and event handling

startup-business-analyst-business-case

31392
from sickn33/antigravity-awesome-skills

Generate comprehensive investor-ready business case document with market, solution, financials, and strategy

dataverse-python-usecase-builder

28865
from github/awesome-copilot

Generate complete solutions for specific Dataverse SDK use cases with architecture recommendations

webiny-use-case-pattern

7955
from webiny/webiny-js

UseCase implementation pattern — DI, Result handling, error types, decorators, CMS repositories, entry mappers, and schema-based permissions. Use this skill to implement, inject, override, or decorate any Webiny UseCase, or to build repositories that persist data via CMS.

edge-case-handling

7385
from kreuzberg-dev/kreuzberg

edge case handling

implementing-siem-use-cases-for-detection

4032
from mukul975/Anthropic-Cybersecurity-Skills

Implements SIEM detection use cases by designing correlation rules, threshold alerts, and behavioral analytics mapped to MITRE ATT&CK techniques across Splunk, Elastic, and Sentinel. Use when SOC teams need to expand detection coverage, formalize use case lifecycle management, or build a detection library aligned to organizational threat profile.

implementing-siem-use-case-tuning

4032
from mukul975/Anthropic-Cybersecurity-Skills

Tune SIEM detection rules to reduce false positives by analyzing alert volumes, creating whitelists, adjusting thresholds, and measuring detection efficacy metrics in Splunk and Elastic

case-writer-hybrid

3891
from openclaw/skills

Expand a structured brief in `content-production/inbox/` into a reusable long-form markdown article draft, then run a local writer / critic / judge quality loop with a constrained humanization pass. Use when Codex needs a stage-1 article draft plus reusable writing sidecars for downstream `generate-image` and `wechat-formatter`.

usmle-case-generator

3891
from openclaw/skills

Generate USMLE Step 1/2 style clinical cases with patient history, physical.

aicodem-xmind-testcase

3891
from openclaw/skills

生成 XMind 格式的测试用例思维导图文件。基于测试用例数据自动生成结构化的 XMind 文件,支持电商消费券、登录、注册、下单等多种测试场景。