Token导航 LogoToken导航

Agent Skill · 开发

axiom-transferable-ref(公理可转移参考)

axiom-transferable-ref 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

axiom-transferable-ref 是开发类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为只读;许可证信息还不明确,第三方扫描已通过,按安装量在开发类的 21,746 个 Skill 里排第 10,088。

总安装 2,411周安装 117GitHub Stars 868下载 1,123核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:axiom-transferable-ref(公理可转移参考)
来源仓库:https://github.com/charleswiltgen/axiom
仓库路径:skills/axiom-transferable-ref
安装命令:
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-transferable-ref
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-transferable-ref

这个 Skill 是做什么的

开发类 Skill 面向写代码、改代码和排查问题,一般会读写仓库文件,部分还会执行构建或测试命令。

axiom-transferable-ref 全面讲解 CoreTransferable 框架与分享表面(ShareLink、DragDrop)集成。适用于实现自定义数据类型拖放、剪贴板复制或系统分享面板扩展功能开发。

涵盖 CodableRepresentation、DataRepresentation 等多种表示类型选择策略。需声明 UTType 并实现 transferRepresentation 协议方可参与系统级数据交换流程。涉及文件传输时应考虑沙盒权限限制,避免尝试访问用户无权读取的系统路径。

来源仓库内路径:skills/axiom-transferable-ref

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-transferabl…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它标注为只读,先用只读任务试一次,确认行为符合预期再扩大使用范围。

常见问题

6 条

axiom-transferable-ref 怎么安装?

在终端执行 npx skills add https://github.com/charleswiltgen/axiom --skill axiom-transferable-ref。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

axiom-transferable-ref 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

axiom-transferable-ref 需要什么权限?

权限级别是只读。该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

axiom-transferable-ref 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

axiom-transferable-ref 用的人多吗?

公开数据是累计安装 2,411 次,近一周安装 117 次,下载 1,123 次,GitHub 868 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

axiom-transferable-ref 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。
  • 标注为只读权限,试用阶段不容易误改本地文件。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理开发类任务、又不想每次都手写提示词的人。
  • 只想先试试效果、不希望它改动本地文件的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

开发类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
skill-vetter

技能审查员 · OpenClaw

8,779,018986操作浏览器MIT-0通过
ontology

本体论 · OpenClaw

6,636,960576只读MIT-0通过
entra-app-registration

内部应用程序注册 · Codex、Claude

6,631,872764接触敏感数据未明确通过
entra-app-registration

内部应用程序注册 · Codex、Claude

3,757,680201接触敏感数据未明确通过
nano-banana-pro

纳米香蕉专业版 · OpenClaw

3,526,898364接触敏感数据MIT-0有提醒
axiom-transferable-ref

公理可转移参考 · 本页

2,411868只读未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

Transferable & Content Sharing Reference

Comprehensive guide to the CoreTransferable framework and SwiftUI sharing surfaces: drag and drop, copy/paste, and ShareLink.

When to Use This Skill

  • Implementing drag and drop (.draggable, .dropDestination)
  • Adding copy/paste support (.copyable, .pasteDestination, PasteButton)
  • Sharing content via ShareLink
  • Making custom types transferable
  • Declaring custom UTTypes for app-specific formats
  • Bridging Transferable types with UIKit's NSItemProvider
  • Choosing between CodableRepresentation, DataRepresentation, FileRepresentation, and ProxyRepresentation

Example Prompts

"How do I make my model draggable in SwiftUI?" "ShareLink isn't showing my custom preview" "How do I accept dropped files in my view?" "What's the difference between DataRepresentation and FileRepresentation?" "How do I add copy/paste support for my custom type?" "My drag and drop works within the app but not across apps" "How do I declare a custom UTType?"


Part 1: Quick Reference

Decision Tree: Which TransferRepresentation?

Your model type...
├─ Conforms to Codable + no specific binary format needed?
│  → CodableRepresentation
├─ Has custom binary format (Data in memory)?
│  → DataRepresentation (exporting/importing closures)
├─ Lives on disk (large files, videos, documents)?
│  → FileRepresentation (passes file URLs, not bytes)
├─ Need a fallback for receivers that don't understand your type?
│  → Add ProxyRepresentation (e.g., export as String or URL)
└─ Need to conditionally hide a representation?
   → Apply .exportingCondition to any representation

Common Errors

Error / SymptomCauseFix
"Type does not conform to Transferable"Missing transferRepresentationAdd static var transferRepresentation: some TransferRepresentation
Drop works in-app but not across appsCustom UTType not declared in Info.plistAdd UTExportedTypeDeclarations entry
Receiver always gets plain text instead of rich typeProxyRepresentation listed before CodableRepresentationReorder: richest representation first
FileRepresentation crashes with "file not found"Receiver didn't copy file before sandbox extension expiredCopy to app storage in the importing closure
PasteButton always disabledPasteboard doesn't contain matching Transferable typeCheck UTType conformance; verify the pasted data matches
ShareLink shows generic previewNo SharePreview provided or image isn't TransferableSupply explicit SharePreview with title and image
.dropDestination closure never firesWrong payload type or view has zero hit-test areaVerify for: type matches dragged content; add .frame() or .contentShape()

Built-in Transferable Types

These work with zero additional code — no conformance needed:

String, Data, URL, AttributedString, Image, Color


Part 2: Making Types Transferable

The Transferable protocol has one requirement: a static transferRepresentation property.

CodableRepresentation

Best for: models already conforming to Codable. Uses JSON by default.

import UniformTypeIdentifiers

extension UTType {
    static var todo: UTType = UTType(exportedAs: "com.example.todo")
}

struct Todo: Codable, Transferable {
    var text: String
    var isDone: Bool

    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(contentType: .todo)
    }
}

Custom encoder/decoder (e.g., PropertyList instead of JSON):

CodableRepresentation(
    contentType: .todo,
    encoder: PropertyListEncoder(),
    decoder: PropertyListDecoder()
)

Requirement: Custom UTTypes need matching UTExportedTypeDeclarations in Info.plist (see Part 4).

DataRepresentation

Best for: custom binary formats where data is in memory and you control serialization.

struct ProfilesArchive: Transferable {
    var profiles: [Profile]

    static var transferRepresentation: some TransferRepresentation {
        DataRepresentation(contentType: .commaSeparatedText) { archive in
            try archive.toCSV()
        } importing: { data in
            try ProfilesArchive(csvData: data)
        }
    }
}

Import-only or export-only variants:

// Import only
DataRepresentation(importedContentType: .png) { data in
    try MyImage(pngData: data)
}

// Export only
DataRepresentation(exportedContentType: .png) { image in
    try image.pngData()
}

Avoid using UTType.data as the content type — use a specific type like .png, .pdf, .commaSeparatedText.

FileRepresentation

Best for: large payloads on disk (videos, documents, archives). Passes file URLs instead of loading bytes into memory.

struct Video: Transferable {
    let file: URL

    static var transferRepresentation: some TransferRepresentation {
        FileRepresentation(contentType: .mpeg4Movie) { video in
            SentTransferredFile(video.file)
        } importing: { received in
            // MUST copy — sandbox extension is temporary
            let dest = FileManager.default.temporaryDirectory
                .appendingPathComponent(UUID().uuidString)
                .appendingPathExtension("mp4")
            try FileManager.default.copyItem(at: received.file, to: dest)
            return Video(file: dest)
        }
    }
}

Critical: The received.file URL has a temporary sandbox extension. Copy the file to your own storage in the importing closure — the URL becomes inaccessible after the closure returns.

SentTransferredFile properties:

  • file: URL — the file location
  • allowAccessingOriginalFile: Bool — when false (default), receiver gets a copy

ReceivedTransferredFile properties:

  • file: URL — the received file on disk
  • isOriginalFile: Bool — whether this is the sender's original file or a copy

Content type precision: .mpeg4Movie only matches .mp4 files. To accept all common video formats (.mp4, .mov, .m4v), use the parent type .movie — or declare multiple FileRepresentations for specific subtypes:

// Broad: accept any video format the system recognizes
FileRepresentation(contentType: .movie) { ... } importing: { ... }

// Or specific: separate handlers per format
FileRepresentation(contentType: .mpeg4Movie) { ... } importing: { ... }
FileRepresentation(contentType: .quickTimeMovie) { ... } importing: { ... }

Import-only: When your type only receives files (drop target, no export), use the import-only initializer — it makes intent explicit and avoids accidental export:

FileRepresentation(importedContentType: .movie) { received in
    let dest = appStorageURL.appendingPathComponent(received.file.lastPathComponent)
    try FileManager.default.copyItem(at: received.file, to: dest)
    return VideoClip(localURL: dest)
}

ProxyRepresentation

Best for: fallback representations that let your type work with receivers expecting simpler types.

struct Profile: Transferable {
    var name: String
    var avatar: Image

    static var transferRepresentation: some TransferRepresentation {
        CodableRepresentation(contentType: .profile)
        ProxyRepresentation(exporting: \.name)  // Fallback: paste as text
    }
}

Export-only proxy (common pattern — reverse conversion often impossible):

ProxyRepresentation(exporting: \.name)  // Profile → String (one-way)

Bidirectional proxy (when reverse makes sense):

ProxyRepresentation { item in
    item.name  // export
} importing: { name in
    Profile(name: name)  // import
}

Combining Multiple Representations

List representations in the transferRepresentation body. Order matters — receivers use the first representation they support.

struct Profile: Transferable {
    static var transferRepresentation: some TransferRepresentation {
        // 1. Richest: full profile data (apps that understand .profile)
        CodableRepresentation(contentType: .profile)
        // 2. Fallback: plain text (text fields, notes, any app)
        ProxyRepresentation(exporting: \.name)
    }
}

Common mistake: putting ProxyRepresentation first causes receivers that support both to always get the degraded version.

Conditional Export

Hide a representation at runtime when conditions aren't met:

DataRepresentation(contentType: .commaSeparatedText) { archive in
    try archive.toCSV()
} importing: { data in
    try Self(csvData: data)
}
.exportingCondition { archive in
    archive.supportsCSV
}

Visibility

Control which processes can see a representation:

CodableRepresentation(contentType: .profile)
    .visibility(.ownProcess)  // Only within this app

Options: .all (default), .team (same developer team), .group (same App Group, macOS), .ownProcess (same app only)

Suggested File Name

Hint for receivers writing to disk:

FileRepresentation(contentType: .mpeg4Movie) { video in
    SentTransferredFile(video.file)
} importing: { received in
    // ...
}
.suggestedFileName("My Video.mp4")

// Or dynamic:
.suggestedFileName { video in video.title + ".mp4" }

Part 3: SwiftUI Surfaces

ShareLink

The standard sharing entry point. Accepts any Transferable type.

// Simple: share a string
ShareLink(item: "Check out this app!")

// With preview
ShareLink(
    item: photo,
    preview: SharePreview(photo.caption, image: photo.image)
)

// Share a URL with custom preview (prevents system metadata fetch)
ShareLink(
    item: URL(string: "https://example.com")!,
    preview: SharePreview("My Site", image: Image("hero"))
)

Sharing multiple items with per-item previews:

ShareLink(items: photos) { photo in
    SharePreview(photo.caption, image: photo.image)
}

SharePreview initializers:

  • SharePreview("Title") — text only
  • SharePreview("Title", image: someImage) — text + full-size image
  • SharePreview("Title", icon: someIcon) — text + thumbnail icon
  • SharePreview("Title", image: someImage, icon: someIcon) — all three

Gotcha: If you omit SharePreview for a custom type, the share sheet shows a generic preview. Always provide one for non-trivial types.

Drag and Drop

Making a view draggable:

Text(profile.name)
    .draggable(profile)

With custom drag preview:

Text(profile.name)
    .draggable(profile) {
        Label(profile.name, systemImage: "person")
            .padding()
            .background(.regularMaterial)
    }

Accepting drops:

Color.clear
    .frame(width: 200, height: 200)
    .dropDestination(for: Profile.self) { profiles, location in
        guard let profile = profiles.first else { return false }
        self.droppedProfile = profile
        return true
    } isTargeted: { isTargeted in
        self.isDropTargeted = isTargeted
    }

Multiple item types — use an enum wrapper conforming to Transferable rather than stacking .dropDestination modifiers (stacking may cause only the outermost handler to fire):

enum DroppableItem: Transferable {
    case image(Image)
    case text(String)

    static var transferRepresentation: some TransferRepresentation {
        ProxyRepresentation { (image: Image) in DroppableItem.image(image) }
        ProxyRepresentation { (text: String) in DroppableItem.text(text) }
    }
}

myView
    .dropDestination(for: DroppableItem.self) { items, _ in
        for item in items {
            switch item {
            case .image(let img): handleImage(img)
            case .text(let str): handleString(str)
            }
        }
        return true
    }

ForEach with reordering — combine with .onMove or use draggable/dropDestination for cross-container moves.

Clipboard (Copy/Paste)

Copy support (activates Edit > Copy / Cmd+C):

List(items) { item in
    Text(item.name)
}
.copyable(items)

Paste support (activates Edit > Paste / Cmd+V):

List(items) { item in
    Text(item.name)
}
.pasteDestination(for: Item.self) { pasted in
    items.append(contentsOf: pasted)
} validator: { candidates in
    candidates.filter { $0.isValid }
}

The validator closure runs before the action — return an empty array to prevent the paste.

Cut support:

.cuttable(for: Item.self) {
    let selected = items.filter { $0.isSelected }
    items.removeAll { $0.isSelected }
    return selected
}

PasteButton — system button that handles paste with type filtering:

PasteButton(payloadType: String.self) { strings in
    notes.append(contentsOf: strings)
}

Platform difference: PasteButton auto-validates pasteboard changes on iOS but not on macOS.

Availability: .copyable, .pasteDestination, and .cuttable are macOS 13+ only — they do not exist on iOS. On iOS, use PasteButton (iOS 16+) for paste, and standard context menus or UIPasteboard for programmatic copy/cut. PasteButton is cross-platform: macOS 10.15+, iOS 16+, visionOS 1.0+.


Part 4: UTType Declarations

System Types

Use Apple's built-in UTTypes when possible — they're already recognized across the system:

import UniformTypeIdentifiers

// Common types
UTType.plainText       // public.plain-text
UTType.utf8PlainText   // public.utf8-plain-text
UTType.json            // public.json
UTType.png             // public.png
UTType.jpeg            // public.jpeg
UTType.pdf             // com.adobe.pdf
UTType.mpeg4Movie      // public.mpeg-4
UTType.commaSeparatedText  // public.comma-separated-values-text

Declaring Custom Types

Step 1: Declare in Swift:

extension UTType {
    static var recipe: UTType = UTType(exportedAs: "com.myapp.recipe")
}

Step 2: Add to Info.plist under UTExportedTypeDeclarations:

<key>UTExportedTypeDeclarations</key>
<array>
    <dict>
        <key>UTTypeIdentifier</key>
        <string>com.myapp.recipe</string>
        <key>UTTypeDescription</key>
        <string>Recipe</string>
        <key>UTTypeConformsTo</key>
        <array>
            <string>public.data</string>
        </array>
        <key>UTTypeTagSpecification</key>
        <dict>
            <key>public.filename-extension</key>
            <array>
                <string>recipe</string>
            </array>
        </dict>
    </dict>
</array>

Both are required. The Swift declaration alone makes it compile, but cross-app transfers silently fail without the Info.plist entry.

Imported vs Exported Types

  • Exported (exportedAs:) — Your app owns this type. Use for app-specific formats.
  • Imported (importedAs:) — Another app owns this type. Use when you want to accept their format.

UTType Conformance

Custom types should conform to system types for broader compatibility:

// Your .recipe conforms to public.data (binary data)
// This means any receiver that accepts generic data can also accept recipes

Common conformance parents: public.data, public.content, public.text, public.image


Part 5: UIKit Bridging

NSItemProvider + Transferable

Bridge between UIKit's NSItemProvider (used by UIActivityViewController, extensions, drag sessions) and Transferable:

// Load a Transferable from an NSItemProvider
let provider: NSItemProvider = // from drag session, extension, etc.
provider.loadTransferable(type: Profile.self) { result in
    switch result {
    case .success(let profile):
        // Use the profile
    case .failure(let error):
        // Handle error
    }
}

When to Use UIActivityViewController

ShareLink covers most sharing needs. Use UIActivityViewController when you need:

  • Custom activity items or excluded activity types
  • UIActivityItemsConfiguration for lazy item provision
  • Custom UIActivity subclasses
  • Programmatic presentation control
struct ShareSheet: UIViewControllerRepresentable {
    let items: [Any]

    func makeUIViewController(context: Context) -> UIActivityViewController {
        UIActivityViewController(activityItems: items, applicationActivities: nil)
    }

    func updateUIViewController(_ vc: UIActivityViewController, context: Context) {}
}

For most apps, ShareLink is sufficient and preferred — it integrates with Transferable natively.


Part 6: Gotchas & Troubleshooting

FileRepresentation Temporary File Lifecycle

The received.file URL in a FileRepresentation importing closure has a temporary sandbox extension. The system may revoke access after the closure returns. Always copy the file:

// WRONG — file may become inaccessible
return Video(file: received.file)

// RIGHT — copy to your own storage
let dest = myAppDirectory.appendingPathComponent(received.file.lastPathComponent)
try FileManager.default.copyItem(at: received.file, to: dest)
return Video(file: dest)

Async Work After File Drop

The FileRepresentation importing closure is synchronous — you cannot await inside it. Copy the file first, return the model, then do async post-processing (thumbnails, transcoding, metadata extraction) on the copied URL:

// WRONG — can't await in the importing closure
FileRepresentation(importedContentType: .movie) { received in
    let dest = ...
    try FileManager.default.copyItem(at: received.file, to: dest)
    let thumbnail = await generateThumbnail(for: dest)  // ❌ compile error
    return VideoClip(localURL: dest, thumbnail: thumbnail)
}

// RIGHT — return immediately, process async afterward
// In your view model or drop handler:
.dropDestination(for: VideoClip.self) { clips, _ in
    for clip in clips {
        timeline.append(clip)
        Task {
            // clip.localURL is the COPY — safe to access anytime
            let thumbnail = await generateThumbnail(for: clip.localURL)
            clip.thumbnail = thumbnail
        }
    }
    return true
}

Representation Ordering

Representations are tried in declaration order. The receiver uses the first one it supports.

// WRONG — receivers always get plain text
static var transferRepresentation: some TransferRepresentation {
    ProxyRepresentation(exporting: \.name)   // ← every receiver supports String
    CodableRepresentation(contentType: .profile)  // ← never reached
}

// RIGHT — richest first, fallbacks last
static var transferRepresentation: some TransferRepresentation {
    CodableRepresentation(contentType: .profile)  // ← apps that understand Profile
    ProxyRepresentation(exporting: \.name)         // ← fallback for everyone else
}

Custom UTType Without Info.plist

If you declare UTType(exportedAs: "com.myapp.type") in Swift but forget the Info.plist entry:

  • In-app transfers work (same process recognizes the type)
  • Cross-app transfers silently fail (other apps can't resolve the type)

This is the most common "works in development, fails in production" issue.

Drop Target Hit Testing

.dropDestination requires the view to have a non-zero frame for hit testing. If drops aren't registering:

// WRONG — Color.clear has zero intrinsic size
Color.clear
    .dropDestination(for: Image.self) { ... }

// RIGHT — give it a frame
Color.clear
    .frame(width: 200, height: 200)
    .contentShape(Rectangle())  // ensure full area is hit-testable
    .dropDestination(for: Image.self) { ... }

Async Loading with loadTransferable

NSItemProvider.loadTransferable is asynchronous. Update UI on the main actor:

provider.loadTransferable(type: Profile.self) { result in
    Task { @MainActor in
        switch result {
        case .success(let profile):
            self.profile = profile
        case .failure(let error):
            self.errorMessage = error.localizedDescription
        }
    }
}

PasteButton Platform Differences

PasteButton auto-validates against pasteboard changes on iOS — the button enables/disables as the pasteboard content changes. On macOS, this automatic validation does not occur. If your macOS app needs dynamic paste validation, monitor UIPasteboard.changedNotification (UIKit) or NSPasteboard change count manually.


Resources

WWDC: 2022-10062, 2022-10052, 2022-10023, 2022-10093, 2022-10095

Docs: /coretransferable/transferable, /coretransferable/choosing-a-transfer-representation-for-a-model-type, /coretransferable/filerepresentation, /coretransferable/proxyrepresentation, /swiftui/sharelink, /swiftui/drag-and-drop, /swiftui/clipboard, /uniformtypeidentifiers

Skills: axiom-photo-library, axiom-codable, axiom-swiftui-gestures, axiom-app-intents-ref

平台分布

Codex

33.31%
按下载量换算374

Claude

31.04%
按下载量换算349

Cursor

20.73%
按下载量换算233

Gemini CLI

9.98%
按下载量换算112

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills