Sipeed I2C and SPI Hardware Control
sipeed/picoclaw
Reads and controls I2C and SPI peripherals on Sipeed boards such as LicheeRV Nano, MaixCAM and NanoKVM through the i2c and spi tools.
Explains how to declare a firmware patch in a vphone patch set, add a new set, or write a preset, including naming, gating and the checks that catch undeclared patches.
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install Lakr233/vphone-cli authoring-patch-sets --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .claude/skills && cp -r skills-src/Skills/authoring-patch-sets .claude/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.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/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .claude/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-setsType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install Lakr233/vphone-cli authoring-patch-sets --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .agents/skills && cp -r skills-src/Skills/authoring-patch-sets .agents/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .agents/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install Lakr233/vphone-cli authoring-patch-sets --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/Skills/authoring-patch-sets .cursor/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .cursor/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/Lakr233/vphone-cli.git --path Skills/authoring-patch-sets--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install Lakr233/vphone-cli authoring-patch-sets --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/Skills/authoring-patch-sets .gemini/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .gemini/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install Lakr233/vphone-cli authoring-patch-setsInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .github/skills && cp -r skills-src/Skills/authoring-patch-sets .github/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .github/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install Lakr233/vphone-cli authoring-patch-sets --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/Lakr233/vphone-cli.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/Skills/authoring-patch-sets .opencode/skills/authoring-patch-sets && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "authoring-patch-sets" agent skill from https://github.com/Lakr233/vphone-cli/tree/main/Skills/authoring-patch-sets into .opencode/skills/authoring-patch-sets/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "authoring-patch-sets", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
authoring-patch-setsExplains how to declare a firmware patch in a vphone patch set, add a new set, or write a preset, including naming, gating and the checks that catch undeclared patches.
In the vphone project every firmware patch is declared in a patch set, selected by a preset and written only if its gate allows. A patch that exists in code but in no manifest still applies; it just cannot be turned off and prints a warning on every run. The skill explains the three layers: a patch (`VPhonePatchDeclaration`) listed in a set's patches array, a set (`VPhonePatchSetManifest`) in a Swift file under `FirmwarePatcher/PatchSets/` or in a `.vphonepatchset` bundle's manifest, and a preset (`VPhonePatchPreset`) in a plist.
To add a patch, you write it as usual with the ARM64 disassembler and encoder, note the `patchID` it emits, declare it in the right set, then build, run the golden corpus and grep the logs to confirm the line 'declared by no patch set' is absent. Identifiers follow a component-effect-name scheme, where the component names the boot stage or file the bytes land in (for example kernel, devicetree, dyld or a system binary) and the effect (boot, exp or cfw) is derived from the patch's flags. The excerpt is cut off before the sections on version gates, presets and out-of-tree sets.
4 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit aa20eb8. It shows what the files ask for, not the result of running them.
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.
Shell commands in SKILL.md call:
xcodebuildFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Authoring VPhone Patch Sets loads about 4.6k tokens when it runs. Until then it costs about 77 tokens; SKILL.md has 2,086 words of instructions outside code blocks.
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.
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.
The full file from Lakr233/vphone-cli at commit aa20eb8, republished under its MIT licence (© Lakr233). 2,086 words, ~4,554 tokens.
.claude/skills/authoring-patch-sets/SKILL.md (or your agent's skills folder).Every patch this project applies is declared in a patch set, selected by a preset, and written only if the gate says so. A patch that exists in code but in no manifest still applies — it just cannot be turned off, and it prints a warning on every run. Declaring it is what makes it real.
| Layer | Type | Where |
|---|---|---|
| A patch | VPhonePatchDeclaration | a set's patches array |
| A set | VPhonePatchSetManifest | FirmwarePatcher/PatchSets/*.swift, or a .vphonepatchset's Contents/Resources/Manifest.plist |
| A preset | VPhonePatchPreset | VPhoneExecutable/VPhoneVirtualization/Resources/patches_presets/*.plist |
The types live in VPhoneExecutable/VPhoneCommand/VPhonePatchKit/PatchSet/. The
nine in-tree sets and the two shipped presets live in
VPhoneExecutable/VPhoneCommand/FirmwarePatcher/PatchSets/, listed by
FirmwarePatchSetCatalog.
Write the patch as usual. Nothing about patch code changes: same
ARM64Disassembler matching, same ARM64Encoder / ARM64 constants for
replacement bytes, same emit(...). Follow the kernel patcher guardrails in
AGENTS.md.
Note the record identifier your patch emits — the patchID: you pass to
emit. That is what ties the patch to its declaration.
Declare it in the right set, with the identifier being the record
identifier, or the part before .<site> when the patch writes several
sites. Name it by the scheme in Naming:
VPhonePatchDeclaration(
identifier: "kernel-boot-my_patch",
title: "What it is, in three or four words",
summary: "What it does and why the guest needs it. One or two sentences.",
target: .firmware(.kernelcache),
applicability: VPhonePatchApplicability(iOSBase: .major(27)),
bootEssential: true,
)Build and run the golden corpus. A record no declaration covers prints
[!] <component>: <id> is declared by no patch set; applying it anyway. Grep
the logs for declared by no patch set — it must be absent.
A patch identifier is {component}-{effect}-{name}, hyphen-separated:
avpbooter, ibss, ibec, llb,
txm, kernel, devicetree, dyld (the shared cache), preboot, or
system-<binary> for a guest system binary or file
(system-seputil-boot-gigalocker_uuid, system-vphoned-boot-install).boot if bootEssential, else exp if
standard leaves it off, else cfw. A patch that changes either property is
renamed with it.[a-z0-9_], no dots or hyphens.Every patch identifier names its component, effect and patch in
FirmwarePatchSetCatalogTests checks the shape, the effect and uniqueness for
every bundled declaration.
A declaration covers its own record and any record <identifier>.<site> —
only a dot starts a site:
kernel-boot-kcall10 covers kernel-boot-kcall10.sy_call, kernel-boot-kcall10.sy_munge, …kernel-boot-sandbox_ext covers kernel-boot-sandbox_ext.3 and every other indexkernel-boot-post_validation does not cover kernel-boot-post_validation_unsignedkernel-cfw-debugger does not cover kernel-cfw-debuggerlessAn underscore continues a snake_case name, so it never separates a site: emit
.1, not _1.
Pick the granularity a user would want to tick. One declaration per patch method
is usually right — a patch writing four sites that only work together is one
checkbox, because half of it would not boot. Where sites are genuinely
independent, declare them separately: kernel-*-sandbox_* is five declarations,
one per MACF hook, because turning one hook off is a sensible thing to want.
Never let one declaration read as a site of another.
No patch identifier is a record-site prefix of another fails if you do.
applicability is the only correct way to say "this patch is for release X". It
is a structured enum, never a string:
VPhonePatchApplicability(iOSBase: .major(27)) // every 27.x
VPhonePatchApplicability(iOSBase: .release(major: 26, minor: 0)) // exactly 26.0
VPhonePatchApplicability(cloudOS: .atLeast(major: 26, minor: 4)) // 26.4 and later
VPhonePatchApplicability(iOSBase: .oneOf([.release(major: 26, minor: 0), .major(18)]))iOSBase is the iPhone base whose userland is restored into the guest; cloudOS
is the release supplying the kernel and boot chain. Only major and minor are
compared, so 18.6.2 satisfies .major(18).
An unreadable version satisfies only .any. That is deliberate: a patch pinned
to a release must not apply when nothing knows which release this is.
Two rules follow, and they are the ones people get wrong:
.any applicability and block it in standard.Do not add a boolean flag to FirmwarePipeline or a --force-something CLI
flag for this. The patches behind --frida, --force-exc-guard and
--force-dsc-maxslide are declarations now, and all three flags are gone.
Adding another is a regression.
Set bootEssential: true when the guest does not boot without the patch. This
does not prevent it being turned off — an external set replacing it is a
supported case — but it makes the consequence visible: the resolver reports it in
droppedBootEssentials, fw patch logs [!] Boot-essential patches are off:,
and the Launchpad editor warns before letting it be unticked.
A boot-essential declaration must have a summary. The test enforces it: it is
the text someone reads before unticking a box that stops their VM booting.
A set is worth creating when its patches share a reason to be on or off together.
Copy the shape of FirmwareKernelFridaPatchSet.swift — it is the smallest one:
public enum FirmwareMyPatchSet {
public static let identifier = "com.vphone.patchset.my"
public static let manifest = VPhonePatchSetManifest(
identifier: identifier,
name: "My Patches",
summary: "One line on what this set is for",
patches: [ /* declarations */ ],
requires: ["vphone.kernel.base"],
provides: ["vphone.my"],
conflictsWith: [],
after: ["vphone.kernel.base"],
)
}Then:
FirmwarePatchSetCatalog.bundled.FirmwarePipelineComponents.buildComponentList on includesSet(...). This
matters: a patcher left in place while its set is out of the preset emits
records nothing declares, and undeclared records apply. Leaving the set out
has to mean leaving the patcher out.provides names capabilities; a set implicitly provides its own identifier.
requires must be satisfied by some set in the plan or resolution fails.
conflictsWith is enforced symmetrically — either side naming the other is a
conflict, so an older set need not be edited to learn about a newer rival. There
is no Supersedes: a conflict is an error, not a silent winner. after orders
the sets, and a cycle is an error.
Two sets may not declare the same patch identifier. A set that replaces another set's patch gives its version a new identifier, and the preset blocks the original.
Presets are prewritten and reviewed. Nothing in the tool writes one; a VM records only which boxes its owner changed, and those compose on top.
standard is what every VM gets. Any other preset must be asked for with
--preset. Both shipped presets name all nine sets and differ only in their
selection:
<key>Selection</key>
<dict>
<key>Kind</key>
<string>Block</string>
<key>Patches</key>
<array>
<string>kernel-exp-frida_thread_set_state_entitlement_flag</string>
</array>
</dict>Kind is All, Allow or Block — never both lists, because a manifest able to
carry both invites a preset where one silently wins. Use Block for "everything
except"; use Allow only for a deliberately minimal preset, remembering that a
patch added later will not be in it.
When you add or change a preset plist, mirror it in
FirmwarePatchSetCatalog — that Swift copy is what a dev build with no staged
bundle falls back to, and The shipped preset plists match the built-in copies
fails if they drift.
A VM carries three patch records, each with its own writers:
| File | What it says | Written by |
|---|---|---|
<vm>/PatchSelection.plist | what the owner wants: a preset plus the boxes they changed | fw set-patches; vm create (preset only); fw patch (rewrites it with what it ran, --preset included) |
<vm>/PatchPlan.plist | what the last fw patch resolved | fw patch |
<vm>/PatchReceipt.plist | what is live in the guest, part by part | each step that puts patched bytes into the guest |
fw set-patches is how a person changes the first:
vphone-cli fw set-patches lab --preset extended --block kernel-cfw-debugger
vphone-cli fw set-patches lab # back to the preset aloneEach run writes the whole record, and only differences survive it — an
identifier the preset already agrees with is dropped, so a later preset revision
still reaches a VM whose boxes were never touched. The Launchpad's patch editor
reads fw patches --json and writes through this verb rather than touching a VM
bundle itself. Blocking a boot-essential patch is allowed; it warns on stderr.
A selection reaches the guest only through the step that owns the bytes, which
depends on where the patch lands; changing it on a machine that already exists is
covered in Research/Firmware/post_creation_patch_changes.md. In short: the
boot chain follows the plan and reaches the guest only through a restore (or,
for AVPBooter, the next fw patch); guest-side patches follow the current
selection, and cfw install and cfw update-environment apply them both ways —
on, or reverted when turned off — and record the Guest part of the receipt.
vphone-cli fw patches <vm> compares all three records.
If your patch targets the guest, make it revertible: back the file up before
the first write (.bak beside it) or, for the dyld cache, write through a
DyldSharedCacheChunkSet with undo capture so its bytes land in the undo log.
A guest patch with no way back is reported "not revertible" and stays live.
Start from VPhoneExecutable/VPhoneCommand/VPhonePatchSetExample. It is a
complete, building set — one iBEC string rewrite — and the loader tests load it,
so it is kept working. Copy the target, change the identifier, replace the patcher.
An external set is a macOS loadable bundle with the .vphonepatchset extension:
Mine.vphonepatchset/
Contents/
Info.plist CFBundleExecutable names the binary
MacOS/Mine exports vphone_patch_set_principal
Resources/Manifest.plist what the set declares
_CodeSignature/ written by `vphone-cli patchset import`Build it against the VPhonePatchKit.framework the bundle ships — it is built
with library evolution and ships its .swiftinterface, so an out-of-tree set
links against the same copy vphone-cli loads rather than statically linking a
second disassembler. The target needs
LD_RUNPATH_SEARCH_PATHS = @executable_path/../Frameworks so the framework beside
vphone-cli is the one that resolves.
Three things make up the code side, and there is nothing else to implement:
// 1. The entry point. One exported C symbol, copied verbatim.
@_cdecl("vphone_patch_set_principal")
public func makeMyPatchSetPrincipal() -> UnsafeMutableRawPointer {
VPhonePatchSetPrincipal.export(MyPatchSet())
}
// 2. The principal, asked for one patcher per component the manifest declares
// an enabled patch for. The inherited default throws for anything else, so a
// manifest promising a component the code does not handle is a loud error.
public final class MyPatchSet: VPhonePatchSetPrincipal {
public override func makePatcher(
for component: VPhoneFirmwareComponent,
data: Data,
context: VPhonePatchSetContext,
) throws -> any BufferedPatcher {
guard component == .iBEC else {
return try super.makePatcher(for: component, data: data, context: context)
}
return MyPatcher(data: data, gate: context.gate, verbose: context.verbose)
}
}
// 3. A BufferedPatcher per component: `patchedData` is how the pipeline reads the
// bytes back, and `gate` is how a per-VM checkmark reaches your patch sites.Not NSPrincipalClass, even though that is the usual way a loadable bundle names
its entry point. PatchKit is built for library evolution, so a subclass of
VPhonePatchSetPrincipal has a resilient superclass and its metadata is realized
at first use, not at image load; the class is therefore not registered with the
ObjC runtime when the bundle is mapped, NSClassFromString cannot find it, and
Bundle.principalClass silently returns whichever class was registered. The
exported symbol has none of that.
context carries what the plan resolved: iOSBase and cloudOS, the gate, the
preset's parameters, and verbose. Ask the gate before you write, never after —
a patch whose records are already in the buffer cannot be turned off.
Set MinimumPatchKitVersion to the API version you need. A set requiring a newer
PatchKit than the bundle has is refused with a readable error instead of failing
in the dynamic loader.
Then import it, which is also what signs it:
vphone-cli patchset import ./Mine.vphonepatchset # copies into ~/.vphone/patchsets, ad hoc signs
vphone-cli patchset list # and says whether it still matches the importA set straight out of Xcode is linker ad hoc signed: the Mach-O has a signature
but the bundle seals no resources, so codesign --verify rejects it. Import runs
one codesign --force --sign - pass over the bundle, which is what fixes that.
The signature is re-checked from disk at every load, so a set edited afterwards
stops loading until it is imported again.
A preset references one by identifier and path:
<dict>
<key>Kind</key><string>External</string>
<key>Identifier</key><string>com.example.patchset.mine</string>
<key>Path</key><string>/path/to/Mine.vphonepatchset</string>
</dict>Both are required: the manifest found at that path must declare that identifier, or replacing the file would silently change which patches a preset applies.
Such a preset goes in ~/.vphone/patches_presets/, not in the bundle: shipped
presets live in a sealed bundle and never reference anything outside it. A user
preset cannot claim an identifier a shipped one already has, so nothing can
redefine standard.
A loaded set patches the boot chain only. Every declared patch must target a firmware component; a guest-side target is refused at import, because the guest half of an install is the privileged step and loads no external set at all.
Security boundary. Root cfw install loads bundled sets only. An external
set reaches a privileged run only after the Launchpad helper has imported it and
pinned its cdhash. Unsigned or invalidly signed sets are ad hoc re-signed at
import, not at load. Do not add a path that lets root open an arbitrary file.
The honest limit: a loaded set is code in the patching process. The gate is what makes its patches selectable, and a patcher that ignores the gate applies anyway. What does hold is the signature check at load and the rule above.
# Build
xcodebuild -workspace VPhone.xcworkspace -scheme VPhoneCommand -configuration Debug \
-destination 'platform=macOS,arch=arm64' -derivedDataPath .build/XcodeCommand build
# What the catalogue now says
vphone-cli fw patches # for a person
vphone-cli fw patches --json # what the Launchpad editor reads
# The model and catalogue tests
xcodebuild -workspace VPhone.xcworkspace -scheme FirmwarePatcherTests -configuration Debug \
-destination 'platform=macOS,arch=arm64' -derivedDataPath .build/XcodeCommand test-without-buildingThe suites that must pass: Version requirements, Patch selection,
Patch declarations, Plan resolution, Patch gate,
Bundled patch set catalogue. Reference-fixture suites fail on machines without
ipsws/ref_extract; that is an environment gap, not a regression.
Then verify byte-identity for anything you did not intend to change. Patching the
same firmware with the same preset must produce the same bytes, and standard
must keep producing what it produced before your change unless changing that was
the point.
Finally: for any change applying new patches, update
Research/0_binary_patch_comparison.md. That is a standing rule in AGENTS.md,
and a new declaration with no research note is an incomplete change.
© Lakr233, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in Skills/authoring-patch-sets of Lakr233/vphone-cli.
Open the folder on GitHubat commit aa20eb8
Authoring VPhone Patch Sets 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.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Authoring VPhone Patch Sets this skillLakr233/vphone-cli | 15k | — | ~4.6k | Automated safety check: Pass | MIT | |
| Sipeed I2C and SPI Hardware Controlsipeed/picoclaw | 30k | — | ~578 | Automated safety check: Pass | MIT | |
| RuView Hardware Setupruvnet/RuView | 97k | — | ~1.8k | Automated safety check: Notes | MIT | |
| Esp32 Firmware Engineeralxv2016/folloup-sticky | 115 | 1 repos | ~3.8k | Automated safety check: Pass | GPL-3.0 | |
| ExecuTorch Binary Size Reductionpytorch/executorch | 5.1k | — | ~793 | Automated safety check: Pass | Custom licence | |
| RuView mmWave Radar Setupruvnet/RuView | 97k | — | ~907 | Automated safety check: Notes | MIT |
sipeed/picoclaw
Reads and controls I2C and SPI peripherals on Sipeed boards such as LicheeRV Nano, MaixCAM and NanoKVM through the i2c and spi tools.
ruvnet/RuView
Brings a RuView CSI sensing node online by building ESP32-S3 or ESP32-C6 firmware, flashing the board, provisioning WiFi and checking the serial output.
alxv2016/folloup-sticky
ESP32 firmware engineering for ESP-IDF projects. An agent skill from alxv2016/folloup-sticky.
pytorch/executorch
Measures and shrinks the ExecuTorch runtime binary by building a size test, analyzing it with bloaty and landing each reduction as its own pull request.
ruvnet/RuView
Sets up and runs 60 GHz and 24 GHz mmWave radar sensing on ESP32 boards in RuView, alone or fused with WiFi CSI.
FastLED/FastLED
Review and implement hardware driver code — DMA safety, interrupt correctness, timing constraints, peripheral register usage, channel drivers, and peripheral mock implementations.
Lakr233/vphone-cli
Looks up symbols and addresses in vphone600 release and research kernel datasets, and cross-references XNU source, with findings that separate fact from inference.
Lakr233/vphone-cli
Drives a virtual iPhone running on an Apple Silicon Mac through the vphone-launchpad-cli, from checking host setup and starting a machine to tapping, typing and installing apps in the guest.
Categories
Explains how to declare a firmware patch in a vphone patch set, add a new set, or write a preset, including naming, gating and the checks that catch undeclared patches. In the vphone project every firmware patch is declared in a patch set, selected by a preset and written only if its gate allows. A patch that exists in code but in no manifest still applies; it just cannot be turned off and prints a warning on every run.
Authoring VPhone Patch Sets fits situations like: adding or changing a patch in FirmwarePatcher; putting a version gate on a patch; making a patch selectable or off by default; building an out-of-tree .vphonepatchset.
Run `npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a claude-code`. Or copy the skill folder (Skills/authoring-patch-sets in Lakr233/vphone-cli) into .claude/skills/authoring-patch-sets in your project. Claude Code loads it when a task matches its description.
Run `npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a codex`. Or copy the skill folder (Skills/authoring-patch-sets in Lakr233/vphone-cli) into .agents/skills/authoring-patch-sets in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add Lakr233/vphone-cli --skill authoring-patch-sets -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/authoring-patch-sets, .gemini/skills/authoring-patch-sets, .github/skills/authoring-patch-sets and .opencode/skills/authoring-patch-sets in your project.
Going by SKILL.md and its folder, Authoring VPhone Patch Sets needs the command-line tools its instructions call (xcodebuild). Our summary lists: A checkout of the vphone-cli repository.
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.
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.
Authoring VPhone Patch Sets is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.6k tokens (SKILL.md is roughly 18k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Authoring VPhone Patch Sets: Sipeed I2C and SPI Hardware Control (sipeed/picoclaw, 30k stars), RuView Hardware Setup (ruvnet/RuView, 97k stars), Esp32 Firmware Engineer (alxv2016/folloup-sticky, 115 stars) and ExecuTorch Binary Size Reduction (pytorch/executorch, 5.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
Lakr233 (a GitHub user) maintains it in Lakr233/vphone-cli, which has 14,949 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on October 7, 2026.
Source: Lakr233/vphone-cli on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.