agentleFS
1Shot-API1Shot-API/skills/ows-branding-layer/SKILL.md

ows-branding-layer

Skill1 starsChanged 7 days agoMITView on GitHub

Teach an agent how to scaffold and extend an OWS Branding Layer in any repository. UI, flow ownership, and display queuing stay app-owned. Published packages provide thin protocol helpers (RpcHelper, SignHelper, CredentialsHelper, showSignerCeremonyPanel) — not a module/registry runtime. When a local clone of open-wallet is available (multi-root workspace), prefer grepping examples/general-wallet over guessing from this skill alone. Then invoke /ows-branding-layer or ask to build a branding wallet. Details: references/architecture.md Details: references/packages.md Copy and track progress. Order matches a typical first…

  • Installs packages

The file

We split this skill into the rules it gives an agent

6 rules. About 0 are common, 1 is distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    When a local clone of open-wallet is available (multi-root workspace), prefer grepping examples/general-wallet over guessing from this …

    line 22
  2. Very specific:

    Prefer OWSWallet.prepare() → register handlers → start().

    line 134
  3. Distinctive:

    Prefer methods on objects over free helpers when logic belongs to one class.

    line 193
  4. Very specific:

    Do not vendor Postmate — use the postmate package (transitive).

    line 195
  5. Very specific:

    Do not reparent the signer iframe.

    line 196
  6. Very specific:

    Prefer Vite /signer/ at origin root even if the branding app uses a subpath base (e.g.

    line 197

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

OWS Branding Layer

Teach an agent how to scaffold and extend an OWS Branding Layer in any repository.

UI, flow ownership, and display queuing stay app-owned. Published packages provide thin protocol helpers (RpcHelper, SignHelper, CredentialsHelper, showSignerCeremonyPanel) — not a module/registry runtime.

When a local clone of open-wallet is available (multi-root workspace), prefer grepping examples/general-wallet over guessing from this skill alone.

Install this skill (consumer / global)

npx skills add 1Shot-API/skills/ows-branding-layer -g -a claude-code -y
# or: npx skills add https://github.com/1Shot-API/skills --skill ows-branding-layer -g -a claude-code -y
# or from a sibling clone: npx skills add ../skills --skill ows-branding-layer -g -a claude-code -y

Then invoke /ows-branding-layer or ask to build a branding wallet.

Architecture (non-negotiable)

Host Layer          @1shotapi/ows-provider     EIP-1193 / credentials proxy
  └── Branding      THIS APP                   UX + Postmate child + helpers
        └── Signing @1shotapi/ows-signer       WebAuthn PRF custody (nested iframe)
  • Host never embeds the Signing Layer. Always Host → Branding → Signing.
  • Signing Layer accepts postMessage only from window.parent when window.parent !== window.top.
  • Passkeys require a secure context on the entire ancestor chain — Host and Branding/Signer must be HTTPS (or localhost / *.localhost).
  • allowLocalAccess is a host OWSProxy option (LAN OID4 from a public branding origin). Do not put it on branding APIs.

Details: references/architecture.md

Packages

PackageRole
@1shotapi/ows-typesBranded primitives, errors, credential types, EIP-1193 tables, CredentialCryptoUtils / PresentationUtils / ProofUtils
@1shotapi/ows-wallet-utilsBranding ↔ Host (OWSWallet, RpcHelper, requestDisplay)
@1shotapi/ows-signer-utilsBranding ↔ Signing (OWSSigner, SignHelper, showSignerCeremonyPanel)
@1shotapi/ows-oid4Optional credentials (CredentialsHelper, HTTP OID4VCI/OID4VP clients)
@1shotapi/ows-signerPlain JS Signing Layer sources (serve as static /signer/)
npm install \
  @1shotapi/ows-types \
  @1shotapi/ows-wallet-utils \
  @1shotapi/ows-signer-utils \
  @1shotapi/ows-oid4 \
  viem
# zod is transitive via ows-wallet-utils — add a direct dep only for custom registerRpc schemas
# Required: serve ows-signer HTML+JS on the same origin as branding (/signer/; CSP frame-ancestors 'self')

Details: references/packages.md

Task checklist

Copy and track progress. Order matches a typical first branding app; specialized wallets may skip EIP-1193 and lead with custom host RPC. The reference wallet (examples/general-wallet) is EIP-1193-first.

Branding Layer Progress:
- [ ] 1. Scaffold — packages + serve Signing Layer on same origin at /signer/
- [ ] 2. Unlock — passkey create/login (`awaitSignerReady` vs `ensureReady`)
- [ ] 3. Display shell — requestDisplay / hide + app-owned modal queue
- [ ] 4. Host RPC — EIP-1193 (RpcHelper + account connect) and/or custom registerRpc (optional `wallet.solana.register` / `wallet.bitcoin.register`)
- [ ] 5. Signing consent — SignHelper + app approval UI
- [ ] 6. Recovery — create/restore via `OWSSigner` auto ceremony panel (no iframe reparent)
- [ ] 7. Credentials — CredentialsHelper + branding `approveAndAcceptOffer` / `approveAndPresent` (optional)
- [ ] 8. EIP-7715 permissions — optional RpcHelper `executionPermissions` hooks (UI in your app; see embedded-wallet)

Task details + exact example paths: references/tasks.md

Minimal boot sequence

Stock Postmate parents only retry the handshake briefly after branding iframe load. Register Postmate.Model via wallet.start() before the nested Signing Layer finishes loading. Use a deferred signer proxy so helpers can register with an OWSSigner-shaped object immediately.

Canonical implementation: examples/general-wallet/src/wallet/WalletProvider.tsx (createDeferredSigner + boot).

import { OWSSigner, SignHelper } from "@1shotapi/ows-signer-utils";
import { OWSWallet, RpcHelper } from "@1shotapi/ows-wallet-utils";
// Optional credentials:
// import { CredentialsHelper } from "@1shotapi/ows-oid4";

const wallet = OWSWallet.prepare({ debug: false });

const signerPromise = OWSSigner.create(signerContainer, signerUrl, {
  hidden: true,
  credentialId: loadCredentialId(),
});
// Proxy that throws until signerPromise resolves — do NOT await signer before start().
const signer = createDeferredSigner(() => signerPromise); // copy pattern from WalletProvider

// Register before start (order in general-wallet):
// account connect → RpcHelper → SignHelper handlers → CredentialsHelper.register()
const rpcHelper = new RpcHelper(providers, wallet, signer, { defaultChainId });

const signHelper = new SignHelper(signer, wallet, {
  getChainId: () => rpcHelper.getChainId(),
  // Branding wrappers: ensureReady → consent + OWSSigner → onAuthenticated
  approveAndSignPersonalMessage,
  approveAndSignTypedData,
  approveAndSignTransaction, // branding: consent + prepare + sign + broadcast
});
for (const [method, handler] of Object.entries(signHelper.handlers)) {
  wallet.registerEip1193(method, handler);
}

// Optional:
// new CredentialsHelper(wallet, { approveAndAcceptOffer, approveAndPresent, … }).register();
// Note: CredentialsHelper(wallet, options); SignHelper(signer, wallet, options)

void wallet.start(); // registers Model immediately — do not await nested signer first
void signerPromise; // background load; UI can paint

Prefer OWSWallet.prepare() → register handlers → start(). Do not use a module install runtime.

Split readiness in your app:

APIMeaning
awaitSignerReady()Nested Signing Layer iframe + OWSSigner loaded
ensureReady()Signer loaded and unlocked / onboarded (passkey) — for connect, credentials, recovery create
ensureOnboardedForSigning()Setup/login only if no credential id; otherwise no-op — for branding signed-action gates
onAuthenticatedAfter successful sign / send (inside branding approveAndSign*): set unlocked + refresh addresses

For custom RPCs such as eth_sendTransaction or future ERC-7710 sends, use the same centralized signed-action gate: setup-only before consent when the credential is missing; one passkey ceremony for the sign itself when the credential is known.

Restore-backup must use awaitSignerReady only — calling ensureReady first can force setup/login before recovery.

Solana Host wire (wallet.solana.register)

Hosts that call proxy.solana.registerSolanaWallet() (Wallet Standard) or proxy.solana.* need Branding handlers. Register the full IOpenWalletSolanaProvider:

wallet.solana.register({
  async getAccountAddress() {
    await ensureReady();
    // session → storage → signer.solana.getAccountAddress()
    return address;
  },
  async signMessage(params) {
    // requestDisplay → SolanaSignModal consent → signer.solana.signMessage
    // return { signatures: SolanaSignature[] }
  },
  async signIn(params) {
    // Resolve SIWS defaults → SiwsModal → signer.solana.signMessage([utf8])
    // return { account, signedMessage: base64, signature }
  },
  async signTransaction(params) {
    // Cluster bind → decode/summary + simulate (warn) → SolanaSignAndSendModal
    // → signer.solana.signTransaction → { signatures }
  },
  async signAndSendTransaction(params) {
    // Same consent → sign → attach wire → Alchemy sendRawTransaction
    // → { signature: SolanaTransactionHash }
  },
});

Tx ownership: Branding owns Alchemy simulate/submit for signAndSendTransaction. Fee payer must be the user; reject extra required signers. Hosts never pass an Alchemy key.

Mirror pattern: embedded-wallet registerSolanaProvider + SolanaSignModals (and registerBitcoinProvider for Bitcoin). Configure copy keys: copy.solanaSign, copy.siws, copy.solanaSignAndSend, copy.solana (shell + SPL Add Asset / rent warnings).

Solana SPL / tracked assets

Unify EVM + Solana under one KnownAsset / TrackedAsset model with EAssetType.Spl (do not overload Erc20). Refined aliases: SolanaKnownAsset / SolanaTrackedAsset. Persist ataAddress (SolanaATAAddress from ows-types) + ataRentPaid on tracked rows only — never put ATA on catalog KnownAsset. TrackedAssetId for Solana is case-preserving base58 (${chainId}:${mint}).

Host addAsset accepts Solana CAIP + mint; Branding should resolve catalog mints only for MVP, ensureAta (CreateIdempotent; user pays rent), then trackedAssetRepository.add with ATA fields. Primary UI never shows ATA; Receive = wallet pubkey + short “senders create token accounts” copy. SPL send may include dest CreateIdempotent + rent line on the confirm sheet.

Hard rules (from OWS)

  1. Branded types from @1shotapi/ows-types — use constructors (EVMAccountAddress(...)), never as casts.
  2. No deprecations during pre-1.0 — rename and update all call sites.
  3. Prefer methods on objects over free helpers when logic belongs to one class.
  4. Set iframe allow for WebAuthn/clipboard before navigation (OWSSigner / host OWSProxy already do this).
  5. Do not vendor Postmate — use the postmate package (transitive).
  6. Do not reparent the signer iframe. Passphrase / Confirm UI is shown by OWSSigner via showSignerCeremonyPanel (bottom ceremony strip). Prefer that over manual overlaySignerIframe.
  7. Prefer Vite /signer/ at origin root even if the branding app uses a subpath base (e.g. /wallet/).

Reference implementation

Canonical React + Vite + Tailwind demo: examples/general-wallet in 1Shot-API/open-wallet.

ConcernStart here
Boot / deferred signersrc/wallet/WalletProvider.tsx
Account connectsrc/ows/registerAccountConnect.ts
Sign consentsrc/ows/registerApprovalSigning.ts, src/components/modals/SignModals.tsx
Credentialssrc/ows/registerCredentialsProvider.ts, src/components/modals/CredentialModals.tsx
Recoverysrc/components/modals/BackupModals.tsx
Serve signervite.config.ts, scripts/copy-signer.mjs, signer-static/index.html

Out of scope for this skill

  • Host Layer apps (ows-provider) — separate concern (allowLocalAccess, flyout chrome)
  • Implementing or modifying ows-signer internals
  • Publishing npm packages / changesets
  • Shared React/Tailwind UI kits (apps own their UI)
  • Calling PresentationUtils / SD-JWT low-level APIs unless you bypass CredentialsHelper

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.