Install
$ agentstack add skill-skiptools-skills-skip-lite-transpilation ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Skip Lite Transpilation Rules
CRITICAL: swift build does NOT validate Kotlin transpilation. You MUST run swift test to catch transpilation errors.
This skill is for Skip Lite (transpiled). If the module's Skip/skip.yml contains mode: 'native', you're in Skip Fuse, not Lite — most of the rules here (integer overflow, Double == Int, Foundation.sqrt, etc.) do not apply. See [skip-fuse](../skip-fuse/SKILL.md) for the Fuse workflow. The rules below still apply to any #if SKIP block inside a Fuse module (those blocks are transpiled to Kotlin even in Fuse mode).
Impact: CRITICAL — Silent Data Corruption
Integer Overflow
Swift Int is 64-bit. Kotlin Int is 32-bit (max ~2.1 billion). Intermediate arithmetic silently overflows in Kotlin.
// BAD: silently wrong on Android
let product = a * b // if a * b > 2,147,483,647
// GOOD: use Int64 for large values
let product = Int64(a) * Int64(b)
Impact: HIGH — Kotlin Compile Errors
Double-to-Int Comparison
// BAD — Kotlin compile error
if someDouble == 0 { }
// GOOD
if someDouble == 0.0 { }
Foundation-Qualified Math
// BAD — Kotlin compile error
let x = Foundation.sqrt(2.0)
// GOOD
let x = sqrt(2.0)
String.append(Character)
// BAD — Kotlin compile error
result.append(someCharacter)
// GOOD
result += String(someCharacter)
Array.remove(atOffsets: IndexSet) in non-SwiftUI modules
The Array.remove(atOffsets:) method that pairs with SwiftUI's .onDelete { offsets in ... } is an extension on RangeReplaceableCollection provided by SwiftUI, not by Foundation. A pure-data module that doesn't import SwiftUI won't have it — the compiler error is No exact matches in call to instance method 'remove'.
// BAD — in a model module that doesn't import SwiftUI
import Foundation
public func remove(at offsets: IndexSet) {
items.remove(atOffsets: offsets) // 'remove' not found
}
// GOOD — expose an Int-array API and let the view convert
public func remove(at indices: [Int]) {
for index in indices.sorted(by: >) where index ` — Kotlin can't add a protocol to an existing type. See [`references/swift-kotlin-rules.md`](references/swift-kotlin-rules.md) for the full pattern and replacement examples.
### `String(describing:)` doesn't transpile
Use string interpolation instead:
```swift
// BAD — Kotlin sees String(describing = value), not a valid constructor
let s = String(describing: someValue)
// GOOD
let s = "\(someValue)"
weak / unowned are silently ignored
Skip uses Kotlin's GC. weak and unowned compile but produce strong references on Kotlin. If you use weak to detect deallocation (weakRef.object == nil as a signal), the check will lie.
deinit becomes Kotlin finalize and may not run
Indeterminate timing, may never execute. Don't put critical cleanup (file close, lock release, network disconnect) in deinit — use defer, try/catch, or an explicit close() method the caller invokes.
Variadic initialisers don't transpile
// BAD
init(_ events: HapticEvent...) { self.events = events }
// GOOD
init(_ events: [HapticEvent]) { self.events = events }
Structs and value semantics
Skip wraps mutable structs in a MutableStruct protocol and inserts .sref() calls automatically to preserve value semantics. You'll see .sref() calls all over your transpiled output; that's normal.
If a struct has var properties but is never modified after construction, you can opt out of the wrapping with the // SKIP @nocopy directive to avoid the copy overhead:
// SKIP @nocopy
struct Config {
var apiURL: URL
var timeout: TimeInterval
}
Two related rules:
- Prefer
final classoverstructfor complex model types with many methods..sref()insertion is fine for plain-data structs but can be subtle with method-heavy ones. - Prefer named methods (
add(),multiply()) over operator overloads for non-trivial types.
Generics — limits and the @inline(__always) escape
Generic type parameters are erased at runtime. is and as? against generic types ignore the generics:
let xs: Any = [1, 2, 3]
if xs is [String] { // True on Kotlin — generics erased
let strings = xs as! [String]
// strings.first crashes — they're actually Ints
}
Also unsupported:
- Static members of generic types that use the type's generic parameters.
- Inner types of generic outer types.
When you need the type available at runtime, annotate the function with @inline(__always) — Skip transpiles it to a Kotlin inline fun :
@inline(__always)
func decode(_ data: Data) throws -> T {
return try JSONDecoder().decode(T.self, from: data)
}
Use sparingly — every call site inlines the body.
The Kotlish dialect and SKIP comment directives
Inside #if SKIP blocks, Skip relaxes its Swift parsing so you can write Kotlin-ish code that looks like Swift to Xcode but transpiles to real Kotlin. This is Kotlish.
When Kotlish can't express what you need (anonymous inner classes, : class references, property delegates), fall back to a SKIP comment directive:
// SKIP INSERT:— inject literal Kotlin at this point. The Swift compiler ignores it.// SKIP REPLACE:— replace the next statement with literal Kotlin.// SKIP DECLARE:— override only the declaration line; transpile the body normally.// SKIP NOWARN— silence a transpiler warning/error on the next line.// SKIP SYMBOLFILE— mark the file as declaration-only; the implementation lives in a parallel.kt.// SKIP EXTERN— JNI / native function reference.// SKIP @nocopy— disableMutableStructwrapping on a struct (see above).// SKIP @nodispatch— prevent automatic dispatch of anasyncfunction onto a Kotlin coroutine context.// SKIP @bridge/@bridgeMembers/@nobridge— control JNI bridging in Fuse mode (see [skip-fuse](../skip-fuse/SKILL.md)).
The directives and the Kotlish syntax (named parameters use : not =; closures use in not ->; wildcard imports use .__ not .*) are covered in detail in [references/swift-kotlin-rules.md](references/swift-kotlin-rules.md).
Kotlin interop — calling Kotlin and Java APIs
#if SKIP
import android.content.Context
let context = ProcessInfo.processInfo.androidContext
let uuid = java.util.UUID.randomUUID().toString()
#endif
For iterating over a Kotlin Map, use entry.value and entry.key:
#if SKIP
for entry in someMap {
let key = entry.key
let value = entry.value
}
#endif
The Swift for (k, v) in dict form does not work for Kotlin Maps.
Supported features
Closures, generics (with limits — see above), optionals, async/await, @Observable, pattern matching, guard/if let, defer, Codable, string interpolation, collection operations (map, filter, reduce).
Unsupported features
Key paths as values, complex macros, C interop (use SkipFFI), Mirror / reflection, variadic generics, UIViewRepresentable. The Array.remove(atOffsets:) SwiftUI-extension trap is its own case — see above.
Diagnosing failures
swift test --filter XCSkipTests # Run transpilation + Kotlin compilation
swift test --filter XCSkipTests -v # Verbose Gradle errors
Kotlin compile errors appear with .kt file paths and line numbers; cross-reference with the original Swift source.
References
- [
references/swift-kotlin-rules.md](references/swift-kotlin-rules.md) — full long-form rules: strings, structs/MutableStruct/.sref(), generics, GC behaviour, Kotlish dialect, every SKIP comment directive with examples,.kotlin()conversion. - [
references/supported-features.md](references/supported-features.md) — feature support table.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: skiptools
- Source: skiptools/skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.