Skip to content
Back to skills

Setup

ASecurity

Wire the self-improving UI harness into this Compose Multiplatform project — scaffold the harness/ ledger + Python tools, install Tier1Assertions + the Roborazzi screenshot-testing convention plugin + an inspection-test template (package-parameterized), and print the build wiring. Short interview fills project slots (base package, target module). Trigger phrases: "set up the ui harness", "install ui-harness", "wire the compose ui harness", "scaffold the screenshot harness".

  • 10 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 6, 2026
developmentpythonjavakotlinshellbashtestinggit

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 6, 2026

npx -y skills add ShipWithAI/shipwithai-plugins --skill setup --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Setup?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Setup
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/shipwithai-setup-shipwithai-plugins/badge)](https://www.skillsdirectory.com/skills/shipwithai-setup-shipwithai-plugins)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: setup
description: >
  Wire the self-improving UI harness into this Compose Multiplatform project — scaffold the
  harness/ ledger + Python tools, install Tier1Assertions + the Roborazzi screenshot-testing
  convention plugin + an inspection-test template (package-parameterized), and print the build
  wiring. Short interview fills project slots (base package, target module).
  Trigger phrases: "set up the ui harness", "install ui-harness", "wire the compose ui harness",
  "scaffold the screenshot harness".
argument-hint: "[<base.package>] [--module path/to/feature/impl]"
---

# UI Harness — Setup

Installs the **per-repo half** of the harness so it is committed and shared with the team: the
ledger, the Python tools beside it, and the Kotlin substrate. The agentic half (the `mobile-design`
skill, the `mobile-design-evaluator` agent, and `/ui-iterate` · `/ui-distill` · `/ui-metrics`)
ships with the plugin and is already available.

Bundled sources live under `${CLAUDE_PLUGIN_ROOT}/assets/`.

## 0. Prerequisite probe + interview

- Confirm this is **Compose Multiplatform + Roborazzi + Robolectric** (the substrate's
  assumptions). If not, stop and point at `${CLAUDE_PLUGIN_ROOT}/assets/INTEGRATION.md`.
- **Base package** = `$1`, else infer it from an existing `package` declaration and confirm.
- **Target module** = the `--module` value, else `Glob` for a feature `impl` module and ask which
  one. Derive its `androidHostTest` source root.

## 1. Lay down the ledger + tools (verbatim)

```bash
mkdir -p harness/bin harness/ledger
cp "${CLAUDE_PLUGIN_ROOT}/assets/harness/bin/"*.py             harness/bin/
cp "${CLAUDE_PLUGIN_ROOT}/assets/harness/ledger/README.md"    harness/ledger/README.md
cp "${CLAUDE_PLUGIN_ROOT}/assets/harness/ledger/screen-aliases.json" harness/ledger/screen-aliases.json
: > harness/ledger/findings.jsonl    # committed, append-only; starts empty
```

Confirm the tools run here: `python3 harness/bin/test_aggregate_ledger.py` (and the two sibling
`test_*.py`) should all pass.

## 2. Install the deterministic asserter

Copy `Tier1Assertions.kt.tmpl` into the target module's `androidHostTest` `testing` package,
replacing the token with the real package. **Substitute the §0 interview values into the shell
vars below and validate them first** — never splice an unvalidated package/path into the shell,
and don't feed the package to `sed` (a `/` in it breaks the `s///` delimiter):

```bash
BASE_PKG="<base.package>"          # from §0, e.g. com.acme.app
MODULE="<module>"                  # from §0, e.g. feature/foo/impl
MODULE_SUFFIX="<module-suffix>"    # package tail under BASE_PKG, e.g. feature.foo.impl

# reject anything that isn't a plain Java package / module path
case "$BASE_PKG"      in *[!A-Za-z0-9._]*|"") echo "invalid base package"; exit 1;; esac
case "$MODULE_SUFFIX" in *[!A-Za-z0-9._]*|"") echo "invalid module suffix"; exit 1;; esac
case "$MODULE"        in *[!A-Za-z0-9._/-]*|/*|*..*) echo "invalid module path"; exit 1;; esac

TESTING_PKG="${BASE_PKG}.${MODULE_SUFFIX}.testing"
DEST="$MODULE/src/androidHostTest/kotlin/${TESTING_PKG//.//}"   # pure-shell '.'→'/', no sed
mkdir -p "$DEST"

# literal token replacement — TESTING_PKG never enters a regex
TESTING_PKG="$TESTING_PKG" python3 - \
  "${CLAUDE_PLUGIN_ROOT}/assets/substrate/Tier1Assertions.kt.tmpl" "$DEST/Tier1Assertions.kt" <<'PY'
import os, re, sys
src, dst = sys.argv[1], sys.argv[2]
text = open(src, encoding="utf-8").read()
open(dst, "w", encoding="utf-8").write(re.sub(r"__TESTING_PACKAGE__.*", os.environ["TESTING_PKG"], text))
PY
```

## 3. Install the convention plugin

Copy `ComposeScreenshotTestingConventionPlugin.kt.tmpl` into `build-logic` (replacing
`__BUILDLOGIC_PACKAGE__`), then register it and apply `id("<prefix>.compose-screenshot-testing")`
in each module that renders screens. See `${CLAUDE_PLUGIN_ROOT}/assets/INTEGRATION.md` for the exact
`build-logic` registration block and the version-catalog aliases it expects.

## 4. Seed one inspection test

Copy `${CLAUDE_PLUGIN_ROOT}/assets/substrate/ScreenInspection.kt.tmpl` next to `Tier1Assertions`,
replace `__PACKAGE__` / `__TESTING_PACKAGE__` / `__SCREEN__` / `__screen__` (the lowercase
single-token screen id), and wire the `TODO`s to render your stateless screen content. Add a
`"<ComposableName>": "<screen-id>"` row to `harness/ledger/screen-aliases.json`.

## 5. Wire the build + gitignore

Follow `${CLAUDE_PLUGIN_ROOT}/assets/INTEGRATION.md` §"Build wiring" and §"gitignore": add the
Roborazzi plugin + version-catalog aliases, register the convention plugin, and gitignore
`harness/ledger/promotions.md`, `harness/ledger/metrics.md`, and the
`build/outputs/roborazzi/_inspect_*.png` / `*_findings.jsonl` sidecars (keep
`harness/ledger/findings.jsonl` **committed**).

## 6. Smoke-test the loop

Run `/ui-iterate <YourScreen>` once. It should render the matrix, run Tier-1, dispatch the
evaluator in a fresh lane, and fold findings into `harness/ledger/findings.jsonl`. If it produces a
`_verdict.md`, the harness is live.

> The six coupling points (package, module coords, ledger root, sidecar glob, catalog aliases,
> screen-alias map) are all touched above. Everything else is project-agnostic.

Files in this skill

  • SKILL.md5.1 KB
  • evals.json1.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.