Skip to content

Add the device debug/MCP loops to the generated agent skill, and give the archetype the Initializr's layout - #5864

Merged
shai-almog merged 8 commits into
masterfrom
issue-5699-skill-mcp-ondevice
Sep 19, 2026
Merged

shai-almog merged 8 commits into
masterfrom
issue-5699-skill-mcp-ondevice

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

Closes #5699 — partly. Two of the three requests are real and are implemented here; the first one has already landed.

What the issue asked for, and what it got

1. An MCP reference in the generated skill — already there. The issue was filed against ac826b1; references/mcp-agent-control.md has landed since, and AGENTS.md and SKILL.md already route to it. No new references/mcp.md. What was genuinely missing from it is the device half, so it gains a short section pointing at the new reference.

2. Real-device Android and iOS references — added. New references/on-device-debugging.md:

  • Android: android.onDeviceDebug, cn1:buildAndroidOnDeviceDebug or a local buildAndroidGradleProject + assembleDebug, cn1:android-on-device-debugging, JDWP on 5005, and the flags that matter (deviceSerial, wireless, apk, skipInstall, waitForAttach).
  • iOS: the four ios.onDeviceDebug hints, proxyHost staying 127.0.0.1 only for the native simulator, the app dialling the proxy on 55333 while the debugger attaches on 8000, and the invocation limits that make an expression silently refuse to evaluate.
  • Reaching device-side MCP: adb forward on Android, nothing at all on the iOS simulator, a usbmux relay on a physical iPhone. That last one is stated as the route rather than as something Codename One ships, because no goal tunnels it.

references/debugging.md and the SKILL.md lookup table now route to it.

3. Generated-project parity — fixed. The Initializr writes AGENTS.md, the skill under .agent-skills/codename-one/, and a thin stub at .claude/skills/codename-one/SKILL.md. The archetype wrote only the full skill under .claude/, so an archetype-generated project had no root pointer and no vendor-neutral copy — an agent that doesn't happen to know Claude Code's directory layout never found the skill. The archetype now stages all three from the same files, and strips all three for Java 8 the way it already stripped .claude/.

AGENTS.md and the Claude stub move out of GeneratorModel's string constants into files, precisely because the archetype now needs them too: a second copy is how the two generators drifted apart in the first place.

The developer guide's MCP chapter gets the same device-attachment paragraph, since it said the transport works on a phone and then never said how to reach the port.

Verification

  • scripts/tests/generate-initializr-fixtures.py — real Initializr ZIPs across every IDE and both Java versions; the Java 17 ones carry the new reference and the extended AGENTS.md, the Java 8 ones carry none of it.
  • Clean-built the archetype and generated a project: -DjavaVersion=17 produces AGENTS.md + .agent-skills/codename-one/ (37 files) + the .claude stub; -DjavaVersion=8 produces none of them.
  • Cn1AppArchetypeCertificateWizardTest gains a test pinning the three-part layout; probed by reverting the pom's target path, which fails it.
  • GeneratorModelMatrixTest extended for the new reference and the new AGENTS.md pointer.
  • check-control-characters.py clean; check-copyright-headers.sh --base <merge-base> clean.

🤖 Generated with Claude Code

@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 18, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-19T05:47:23.232017Z 91ca3e8 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d291e9c32d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -0,0 +1,29 @@
# AGENTS.md

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the generated AGENTS template from governing source files

Because this template is stored under the reserved name AGENTS.md, agents working on scripts/initializr/common/src/main/resources/** will treat it as repository instructions and be redirected to generated-app paths and commands that do not exist in this source tree. This affects maintenance of the bundled skill itself; store the template under a non-reserved filename and rename it only when staging/generated output, as is already done for the Claude stub.

AGENTS.md reference: scripts/initializr/common/src/main/resources/AGENTS.md:L14-L20

Useful? React with 👍 / 👎.

codename1.arg.ios.onDeviceDebug.proxyHost=127.0.0.1
codename1.arg.ios.onDeviceDebug.proxyPort=55333
# Optional: hold the app at startup until the debugger attaches.
codename1.arg.ios.onDeviceDebug.waitForAttach=true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Disable iOS wait mode for MCP-only sessions

When an agent follows this configuration for an MCP-only iOS session, waitForAttach=true defers the application's lifecycle callback until a JDWP debugger attaches, while the MCP server is started later from MyAppName.start(). The app therefore never reaches the MCP starter unless the user also launches the proxy and attaches a debugger; document that ios.onDeviceDebug.waitForAttach must be false when MCP, rather than JDWP, is the purpose of the session.

AGENTS.md reference: scripts/initializr/common/src/main/resources/AGENTS.md:L23-L25

Useful? React with 👍 / 👎.


The port is on the **device's** loopback, not yours, so it needs a forward:

- **Android device or emulator** — `adb forward tcp:8765 tcp:8765`, then connect to `127.0.0.1:8765` on your machine. Tear it down with `adb forward --remove tcp:8765` when you are done.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Target the selected Android device in MCP forwards

When multiple Android devices or emulators are online—the scenario for which the guide already exposes cn1.android.onDeviceDebug.deviceSerial—these bare adb forward and removal commands are ambiguous and fail instead of forwarding to the device selected by the debug goal. Include adb -s <serial> forward ... and the corresponding targeted removal in this flow so MCP reaches the same device as JDWP.

AGENTS.md reference: scripts/initializr/common/src/main/resources/AGENTS.md:L23-L25

Useful? React with 👍 / 👎.

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 151 screenshots: 151 matched.

Native Android coverage

  • 📊 Line coverage: 9.24% (9184/99417 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.99% (47211/525067), branch 3.55% (1768/49739), complexity 3.52% (1869/53026), method 5.43% (1514/27888), class 10.89% (407/3736)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 9.24% (9184/99417 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.99% (47211/525067), branch 3.55% (1768/49739), complexity 3.52% (1869/53026), method 5.43% (1514/27888), class 10.89% (407/3736)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6367 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.ClassReader – 0.00% (0/1524 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1187 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.MethodWriter – 0.00% (0/922 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/736 lines covered)
      • com.google.common.cache.com.google.common.cache.LocalCache$Segment – 0.00% (0/726 lines covered)
      • okio.okio.Buffer – 0.00% (0/687 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/625 lines covered)
      • org.jacoco.agent.rt.internal_0e20598.asm.org.jacoco.agent.rt.internal_0e20598.asm.Frame – 0.00% (0/570 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 223ms / native 286ms = 0.7x speedup
SIMD float-mul (64K x300) java 87ms / native 79ms = 1.1x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 73.000 ms
Base64 CN1 decode 84.000 ms
Base64 native encode 396.000 ms
Base64 encode ratio (CN1/native) 0.184x (81.6% faster)
Base64 native decode 283.000 ms
Base64 decode ratio (CN1/native) 0.297x (70.3% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • build-hint-catalog: 0 findings (no issues)
    • build-hint-tools: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 181 screenshots: 181 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 699 total, 0 failed, 57 skipped

Benchmark Results

  • Execution Time: 13123 ms

  • Hotspots (Top 20 sampled methods):

    • 7.76% java.util.ArrayList.indexOf (84 samples)
    • 5.91% java.lang.StringBuilder.append (64 samples)
    • 4.80% com.codename1.tools.translator.ByteCodeClass.hasDeclaredMethod (52 samples)
    • 3.88% com.codename1.tools.translator.Parser.cn1EnsureSubclassIndex (42 samples)
    • 3.23% java.lang.System.identityHashCode (35 samples)
    • 2.40% com.codename1.tools.translator.bytecodes.Invoke.resolveDirectTarget (26 samples)
    • 2.22% java.lang.StringCoding.encode (24 samples)
    • 2.12% java.lang.String.equals (23 samples)
    • 2.03% org.objectweb.asm.tree.analysis.Analyzer.findSubroutine (22 samples)
    • 1.66% java.util.IdentityHashMap$KeySet.toArray (18 samples)
    • 1.57% com.codename1.tools.translator.Parser.classIndex (17 samples)
    • 1.57% java.util.HashMap.hash (17 samples)
    • 1.48% java.io.FileOutputStream.writeBytes (16 samples)
    • 1.39% org.objectweb.asm.tree.analysis.Analyzer.analyze (15 samples)
    • 1.20% com.codename1.tools.translator.BytecodeMethod.updateInlinableFieldDependencies (13 samples)
    • 1.20% com.codename1.tools.translator.BytecodeMethod.optimize (13 samples)
    • 1.20% com.codename1.tools.translator.bytecodes.Invoke.findMethodUp (13 samples)
    • 1.11% com.codename1.tools.translator.ByteCodeField.equals (12 samples)
    • 1.11% java.lang.Object.hashCode (12 samples)
    • 1.11% java.util.HashMap.putVal (12 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 160 screenshots: 160 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 268 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 69ms / native 3ms = 23.0x speedup
SIMD float-mul (64K x300) java 57ms / native 3ms = 19.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 160.000 ms
Base64 CN1 decode 94.000 ms
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.286x (71.4% faster)
Image applyMask (SIMD off) 51.000 ms
Image applyMask (SIMD on) 50.000 ms
Image applyMask ratio (SIMD on/off) 0.980x (2.0% faster)
Image modifyAlpha (SIMD off) 39.000 ms
Image modifyAlpha (SIMD on) 44.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.128x (12.8% slower)
Image modifyAlpha removeColor (SIMD off) 54.000 ms
Image modifyAlpha removeColor (SIMD on) 32.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.593x (40.7% faster)

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 148 screenshots: 148 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 252 seconds

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 88ms / native 7ms = 12.5x speedup
SIMD float-mul (64K x300) java 48ms / native 2ms = 24.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 148.000 ms
Base64 CN1 decode 88.000 ms
Base64 native encode 524.000 ms
Base64 encode ratio (CN1/native) 0.282x (71.8% faster)
Base64 native decode 212.000 ms
Base64 decode ratio (CN1/native) 0.415x (58.5% faster)
Base64 SIMD encode 47.000 ms
Base64 encode ratio (SIMD/CN1) 0.318x (68.2% faster)
Base64 SIMD decode 45.000 ms
Base64 decode ratio (SIMD/CN1) 0.511x (48.9% faster)
Base64 encode ratio (SIMD/native) 0.090x (91.0% faster)
Base64 decode ratio (SIMD/native) 0.212x (78.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 8.000 ms
Image createMask (SIMD on) 1.000 ms
Image createMask ratio (SIMD on/off) 0.125x (87.5% faster)
Image applyMask (SIMD off) 38.000 ms
Image applyMask (SIMD on) 26.000 ms
Image applyMask ratio (SIMD on/off) 0.684x (31.6% faster)
Image modifyAlpha (SIMD off) 32.000 ms
Image modifyAlpha (SIMD on) 20.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.625x (37.5% faster)
Image modifyAlpha removeColor (SIMD off) 29.000 ms
Image modifyAlpha removeColor (SIMD on) 22.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.759x (24.1% faster)

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 217 screenshots: 217 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 144 screenshots: 144 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Sep 18, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 149 screenshots: 149 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 1184 seconds

Build and Run Timing

Metric Duration
Simulator Boot 57000 ms
Simulator Boot (Run) 0 ms
App Install 16000 ms
App Launch 3000 ms
Test Execution 360000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 76ms / native 3ms = 25.3x speedup
SIMD float-mul (64K x300) java 109ms / native 7ms = 15.5x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 317.000 ms
Base64 CN1 decode 124.000 ms
Base64 native encode 653.000 ms
Base64 encode ratio (CN1/native) 0.485x (51.5% faster)
Base64 native decode 302.000 ms
Base64 decode ratio (CN1/native) 0.411x (58.9% faster)
Base64 SIMD encode 57.000 ms
Base64 encode ratio (SIMD/CN1) 0.180x (82.0% faster)
Base64 SIMD decode 74.000 ms
Base64 decode ratio (SIMD/CN1) 0.597x (40.3% faster)
Base64 encode ratio (SIMD/native) 0.087x (91.3% faster)
Base64 decode ratio (SIMD/native) 0.245x (75.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 8.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.500x (50.0% faster)
Image applyMask (SIMD off) 88.000 ms
Image applyMask (SIMD on) 37.000 ms
Image applyMask ratio (SIMD on/off) 0.420x (58.0% faster)
Image modifyAlpha (SIMD off) 154.000 ms
Image modifyAlpha (SIMD on) 43.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.279x (72.1% faster)
Image modifyAlpha removeColor (SIMD off) 88.000 ms
Image modifyAlpha removeColor (SIMD on) 100.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.136x (13.6% slower)

@shai-almog

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 91ca3e87df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +68 to +73
```properties
codename1.arg.ios.onDeviceDebug=true
codename1.arg.ios.onDeviceDebug.proxyHost=127.0.0.1
codename1.arg.ios.onDeviceDebug.proxyPort=55333
# Optional: hold the app at startup until the debugger attaches.
codename1.arg.ios.onDeviceDebug.waitForAttach=true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add the local-network privacy hint for physical iPhones

When this flow is used on a physical iPhone running iOS 14 or later, setting proxyHost to the developer machine's LAN address makes the debugger perform local-network access, but the documented settings never add codename1.arg.ios.NSLocalNetworkUsageDescription. The on-device-debug injection in IPhoneBuilder adds the proxy keys and an ATS exception but does not synthesize this privacy string, so a newly generated app can be denied or terminated before connecting to the proxy unless it already happens to declare the key. Include the purpose-string hint in the physical-device instructions (or have the builder inject one for on-device-debug builds).

Useful? React with 👍 / 👎.

@shai-almog

shai-almog commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port, REAL shipping pipeline: the hellocodenameone screenshot suite rendered by a binary CROSS-COMPILED on Linux (clang-cl + xwin, WebView2 linked) and RUN on a Windows x64 runner. Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 65ms / native 5ms = 13.0x speedup
SIMD float-mul (64K x300) java 70ms / native 5ms = 14.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 192.000 ms
Base64 CN1 decode 145.000 ms
Base64 SIMD encode 99.000 ms
Base64 encode ratio (SIMD/CN1) 0.516x (48.4% faster)
Base64 SIMD decode 99.000 ms
Base64 decode ratio (SIMD/CN1) 0.683x (31.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 9.000 ms
Image createMask (SIMD on) 4.000 ms
Image createMask ratio (SIMD on/off) 0.444x (55.6% faster)
Image applyMask (SIMD off) 33.000 ms
Image applyMask (SIMD on) 48.000 ms
Image applyMask ratio (SIMD on/off) 1.455x (45.5% slower)
Image modifyAlpha (SIMD off) 37.000 ms
Image modifyAlpha (SIMD on) 28.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.757x (24.3% faster)
Image modifyAlpha removeColor (SIMD off) 32.000 ms
Image modifyAlpha removeColor (SIMD on) 24.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.750x (25.0% faster)

@shai-almog

shai-almog commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port (x64 / Intel-AMD): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, SSE2 SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 64ms / native 5ms = 12.8x speedup
SIMD float-mul (64K x300) java 76ms / native 5ms = 15.2x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 198.000 ms
Base64 CN1 decode 133.000 ms
Base64 SIMD encode 101.000 ms
Base64 encode ratio (SIMD/CN1) 0.510x (49.0% faster)
Base64 SIMD decode 99.000 ms
Base64 decode ratio (SIMD/CN1) 0.744x (25.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 10.000 ms
Image createMask (SIMD on) 28.000 ms
Image createMask ratio (SIMD on/off) 2.800x (180.0% slower)
Image applyMask (SIMD off) 50.000 ms
Image applyMask (SIMD on) 57.000 ms
Image applyMask ratio (SIMD on/off) 1.140x (14.0% slower)
Image modifyAlpha (SIMD off) 47.000 ms
Image modifyAlpha (SIMD on) 56.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.191x (19.1% slower)
Image modifyAlpha removeColor (SIMD off) 54.000 ms
Image modifyAlpha removeColor (SIMD on) 51.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.944x (5.6% faster)

@shai-almog

shai-almog commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Linux port (x64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub x64 runner. Baseline: scripts/linux/screenshots.

@shai-almog

shai-almog commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Linux port (arm64), GTK3/Cairo/Pango, ParparVM bytecode-to-C (no JVM): the hellocodenameone screenshot suite rendered by a native ELF built + run on the GitHub arm64 runner. Baseline: scripts/linux/screenshots-arm.

@shai-almog

shai-almog commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 166 screenshots: 166 matched.
Native Windows port (arm64 / Apple Silicon - Arm): full hellocodenameone screenshot suite rendered offscreen with Direct2D/DirectWrite, plus the real benchmarks (base64 native/CN1/SIMD, image createMask/applyMask/modifyAlpha/PNG/JPEG, NEON SIMD kernels). Compared against the in-repo baseline in scripts/windows/screenshots.

Benchmark Results

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 56ms / native 3ms = 18.6x speedup
SIMD float-mul (64K x300) java 55ms / native 3ms = 18.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 native bridge unavailable (CN1 + SIMD + image benchmarks only)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 245.000 ms
Base64 CN1 decode 128.000 ms
Base64 SIMD encode 64.000 ms
Base64 encode ratio (SIMD/CN1) 0.261x (73.9% faster)
Base64 SIMD decode 63.000 ms
Base64 decode ratio (SIMD/CN1) 0.492x (50.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 7.000 ms
Image createMask (SIMD on) 3.000 ms
Image createMask ratio (SIMD on/off) 0.429x (57.1% faster)
Image applyMask (SIMD off) 40.000 ms
Image applyMask (SIMD on) 18.000 ms
Image applyMask ratio (SIMD on/off) 0.450x (55.0% faster)
Image modifyAlpha (SIMD off) 16.000 ms
Image modifyAlpha (SIMD on) 11.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.688x (31.3% faster)
Image modifyAlpha removeColor (SIMD off) 20.000 ms
Image modifyAlpha removeColor (SIMD on) 12.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.600x (40.0% faster)

shai-almog and others added 8 commits September 19, 2026 11:58
…ype the Initializr's layout

Issue #5699 reports that a fresh Java 17 project tells an agent nothing about
the on-device Maven goals or about driving a build on a phone, and that the
Maven archetype and the web Initializr do not generate the same thing. Both
halves are real; the issue's first request (an MCP reference) is not - it was
filed against ac826b1, and references/mcp-agent-control.md has since landed, so
that part is a pointer rather than a new file.

references/on-device-debugging.md is the new reference. It covers the Android
flow (android.onDeviceDebug, buildAndroidOnDeviceDebug or a local Gradle
assembleDebug, android-on-device-debugging, JDWP on 5005, and the flags that
matter), the iOS flow (the four ios.onDeviceDebug hints, proxyHost being
127.0.0.1 only for the native simulator, the app dialling the proxy on 55333
while the debugger attaches on 8000, and the invocation limits that make an
expression refuse to evaluate), and how to reach the device's MCP port:
adb forward on Android, nothing at all on the iOS simulator, a usbmux relay on
a physical iPhone. The last one is stated as the route rather than as something
we ship - there is no Codename One goal that tunnels it.

Discovery is the other half. The Initializr writes AGENTS.md, the skill under
.agent-skills/codename-one/ and a thin stub at .claude/skills/codename-one/,
while the archetype wrote only the full skill under .claude/ - so an
archetype-generated project had no root pointer and no vendor-neutral copy, and
an agent that does not know Claude Code's directory layout never found the
skill at all. The archetype now stages all three, from the same files, and
strips all three for Java 8 the way it already stripped .claude/.

AGENTS.md and the Claude stub move out of GeneratorModel's string constants and
into files precisely because the archetype now needs them too: a second copy is
how the two generators drifted apart in the first place. They sit flat at the
root of src/main/resources for the same reason skill/ is repackaged into
skill.zip - Codename One's classloader rejects nested resource directories.

Verified end to end: the real Initializr ZIPs (scripts/tests/generate-initializr-fixtures.py)
carry the new reference and the extended AGENTS.md, a project generated with
-DjavaVersion=17 from the rebuilt archetype has all three, and one generated
with -DjavaVersion=8 has none of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The MCP chapter already says the socket transport works on a phone, then stops:
it never says the port is the phone's loopback rather than yours, so the one
thing a reader has to do -- forward it -- is left out. Issue #5699 asks for the
attachment route per platform to be explicit.

Android is adb forward, and worth pairing with android-on-device-debugging's
waitForAttach=false, since an agent session wants the app booted rather than
blocked on a debugger. The native iOS simulator needs nothing, because it shares
the host's network stack. A physical iPhone needs a usbmux relay we do not ship,
which is said plainly rather than left for a reader to discover.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Microsoft.Contractions is enabled for the developer guide, and "does not" in
the new device-attachment section was the one error in the Vale report that
failed "Build Developer Guide Docs". Vale is clean across all 123 guide files
with this.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…duced

The developer-guide gate fails on ANY LanguageTool match, not just on a
non-zero exit, so the three matches in the new paragraph were build-breaking
even with Vale clean.

Two of them are one sentence: "a usbmux TCP relay" trips EN_A_VS_AN (the rule
guesses a vowel sound for a word it has never seen) and MORFOLOGIK on "usbmux"
itself. Neither is a real defect, but the accept list matches the whole flagged
span, and the span for the article rule is the bare "a" -- which cannot be
accepted without accepting every "a" in the guide. So the sentence names the
mechanism in words the dictionary has ("the USB multiplexing channel") and
keeps iproxy, which is already masked as inline code.

libimobiledevice is a genuine proper noun the dictionary lacks, which is
exactly what the accept list is for.

Verified by rendering the chapter with asciidoctor and running
scripts/developer-guide/run_languagetool.py over it: 0 matches with this, and
the pre-commit text still reports the article and spelling matches, so the
check is answering about this prose rather than passing vacuously. Vale is 0
across all 123 guide files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ap, and multi-device adb

Three findings, all real, plus the Vale error the last push left behind.

The AGENTS.md body was stored under that literal name inside this repository,
so an agent working on scripts/initializr/common/src/main/resources/** would
read it as instructions for the Codename One tree -- and it says things like
"app source lives in common/src/main/java" and "run the simulator with
mvn -pl common cn1:run", which describe a GENERATED application and are wrong
here. It moves to agent-skill-agents-md.md and is renamed on staging, the way
the Claude stub already was. The two renames have opposite causes and the
comments now say which is which. The archetype parity test asserts both halves:
the source name exists, and the reserved one does not.

waitForAttach on iOS is not the overlay it looks like. CodenameOne_GLAppDelegate
wraps the VM callback in cn1_debugger_run_when_ready, which stashes the block
until the proxy reports an IDE attached, so start() never runs and a
MCP.startSocketServer call inside it never fires. The reference printed
waitForAttach=true in the hints block and mentioned the false setting only for
Android, which would have left an agent waiting on a port nothing was listening
to. Said in the iOS section, in the MCP section, and in the developer guide.

adb refuses forward and forward --remove outright when several devices are
online rather than picking one, which is the case the reference already hands
deviceSerial for. Both commands now show the -s form.

Vale: "the usual relay for that is" tripped Microsoft.Contractions, which the
previous push introduced while fixing the LanguageTool findings and did not
recheck -- Vale had been re-run before that reword, not after. Both gates are
now confirmed on the final text: Vale 0 across 123 files, LanguageTool 0 on the
rendered chapter.

Re-verified end to end after the rename: the real Initializr ZIPs still carry
AGENTS.md, and a project generated from a clean-built archetype has AGENTS.md,
37 files under .agent-skills/codename-one, the .claude stub, and no file left
under the source name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ot loopback

An on-device-debug app dials OUT to the proxy on the developer's machine. For a
physical iPhone that is an address on the Wi-Fi the two share, and since iOS 14
reaching it is consent-gated local-network access that needs a purpose string
declared up front -- which iOS terminates an app for lacking, as the Matter
block in this same builder already says. The build injected CN1ProxyHost,
CN1ProxyPort, CN1ProxyWaitForAttach and an ATS exemption and stopped there, so
an app built exactly as the guide describes could be killed the moment
cn1_debugger dialled out, leaving the proxy waiting and nothing on the device to
say why. NSLocalNetworkUsageDescription was auto-injected only for Bonjour.

Injected only when the proxy host is not loopback. The native simulator shares
the host's loopback, which is not the local network, and an unnecessary purpose
string puts a prompt in front of a developer who never asked for one -- the
reason the nearby flags are kept apart from one another. Ambiguity resolves
towards declaring it: a host that is not recognisably loopback may still be a
LAN name, and the costs are not symmetric -- a spare string costs one prompt in
a build that is debug-only by construction, a missing one costs a session that
cannot start.

Through applyCatalogPlistEntry rather than putArgument, for the reason the
Matter and CallKit blocks both record: the sweep that copies
ios.NS*UsageDescription hints into privacyUsageDescriptions runs long before
this point and the plist is rendered from that map, so a bare argument set here
would never have been read. It fills only a missing value, so a project with
its own wording keeps it.

Verified against a real generated project rather than by reading. Built the
sample through cn1:buildIosXcodeProject's path (-Dcodename1.buildTarget=ios-source)
and read HelloCodenameOne-Info.plist three times:

  proxyHost=192.168.1.42                   -> the key present exactly once,
                                              plutil -lint OK
  proxyHost=127.0.0.1                      -> the key absent, no prompt added
  proxyHost=192.168.1.42 + own description -> "My own wording." survives

The predicate has its own test. SpotBugs is at zero findings for the module and
the build-hint catalog gate passes; the hint itself is already declared in
IosPrivacy, so nothing new is introduced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…device

The build now declares NSLocalNetworkUsageDescription for a non-loopback proxy
host, so the app is no longer terminated for reaching the LAN with no purpose
string. What that buys is a PROMPT, and a prompt still has to be answered: until
somebody taps it on the phone, the app cannot reach the proxy and the session
looks exactly like a build that never dialled out.

Said where the LAN address is set, because that is the line that causes it, and
said with the symptom attached -- a proxy reporting nothing connected is the
thing an agent will see, and the phone is the last place it would think to look.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#5868 fixed one way the arm flag could go stale and the regression test it added
still failed on Linux CI -- six empty replies in one run. The message that change
added is what made the next step possible: "could not re-arm fd=20", and with an
errno now attached, 17. EEXIST. The descriptor was already in the host's epoll
set.

So the flag was never the real problem. ADD and MOD both mean "watch this
descriptor for these events", and which one is correct depends on whether the
kernel already holds it -- a fact the caller tracks per host, in plain arrays,
written from the accepting thread and read by the host thread. Every way of
getting that wrong ends the same way: epoll answers EEXIST or ENOENT, the caller
sees an IOException, and it drops a connection it has already read a request from
without writing a response. Chasing the individual desync paths one at a time
would have been chasing symptoms; #5868 closed the biggest and six remained.

The tell was that it is Linux-only. The kqueue branch has always been idempotent
-- EV_ADD on a knote that exists updates it rather than refusing -- so the same
mistaken flag costs nothing on macOS, which is why none of this ever reproduced
in a development loop. The asymmetry WAS the bug: the flag is an optimisation
that saves a syscall on the common path, and only epoll was treating it as a
precondition. Each call now falls back to the other, so both platforms mean the
same thing, and the flag keeps the fast path fast without deciding correctness.

registerImpl also returns -errno instead of -1, and Reactor puts it in the
message. What is left after the fallback is a genuine failure, and EBADF (closed
under us) and EPERM (not pollable) ask for different answers from whoever reads
the log -- a line saying only "could not watch fd 20" cost a whole round to
classify.

Measured on Linux, in a container held to 2 CPUs so the window stays open, with
the same churn-around-a-parked-request workload the regression test uses:

  before   3 failures over 4 rounds, each with the re-arm error logged
  after    0 failures over 4 rounds, then 0 across 6767 requests in 8 more

BackendHttpIntegrationTest is green at 72 tests locally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@shai-almog
shai-almog force-pushed the issue-5699-skill-mcp-ondevice branch from 53892f9 to a38bb3c Compare September 19, 2026 09:26
@shai-almog
shai-almog merged commit f7b8992 into master Sep 19, 2026
67 checks passed
@shai-almog
shai-almog deleted the issue-5699-skill-mcp-ondevice branch September 19, 2026 12:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Docs] Add Simulator MCP and real-device workflows to the generated Codename One agent skill

1 participant