{
  "schemaVersion": "1.0",
  "item": {
    "slug": "keychain-bridge",
    "name": "Keychain Bridge",
    "source": "tencent",
    "type": "skill",
    "category": "其他",
    "sourceUrl": "https://clawhub.ai/Euda1mon1a/keychain-bridge",
    "canonicalUrl": "https://clawhub.ai/Euda1mon1a/keychain-bridge",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/keychain-bridge",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=keychain-bridge",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "README.md",
      "SKILL.md",
      "scripts/audit_secrets.py",
      "scripts/get_secret.py",
      "scripts/keychain_helper.py",
      "scripts/migrate_secrets.py"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/keychain-bridge"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/keychain-bridge",
    "agentPageUrl": "https://openagent3.xyz/skills/keychain-bridge/agent",
    "manifestUrl": "https://openagent3.xyz/skills/keychain-bridge/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/keychain-bridge/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Then review README.md for any prerequisites, environment setup, or post-install checks. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Then review README.md for any prerequisites, environment setup, or post-install checks. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Trigger Phrases",
        "body": "\"migrate secrets to keychain\" / \"move secrets\"\n\"check keychain health\" / \"keychain status\"\n\"audit secrets\" / \"check for leaks\"\n\"read secret\" / \"get API key\"\n\"store secret\" / \"write to keychain\"\n\"keychain not working\" / \"security find-generic-password hangs\""
      },
      {
        "title": "Example Usage",
        "body": "User: \"Migrate my secrets to the keychain\"\nAction: python3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot --dry-run\n\nUser: \"Check if the keychain bridge is healthy\"\nAction: Run keychain health check (test write/read/delete cycle)\n\nUser: \"Audit for plaintext secret leaks\"\nAction: python3 SKILL_DIR/scripts/audit_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\nManage secrets via macOS Keychain instead of plaintext files. Eliminates plaintext credential storage while maintaining compatibility with bash-based tools through a file-bridge architecture."
      },
      {
        "title": "Prerequisites",
        "body": "The keyring Python library must be installed for each Python version that will access secrets:\n\npip3 install keyring\n# If multiple Python versions exist (common on macOS):\n/usr/bin/python3 -m pip install keyring\n/opt/homebrew/opt/python@3.14/bin/python3.14 -m pip install --break-system-packages keyring"
      },
      {
        "title": "Check Keychain Health",
        "body": "Verify the keychain bridge is working correctly:\n\npython3 -c \"\nimport keyring\n# Test write\nkeyring.set_password('keychain-bridge-test', 'test', 'hello')\n# Test read\nval = keyring.get_password('keychain-bridge-test', 'test')\nassert val == 'hello', f'Read back {val!r}, expected hello'\n# Cleanup\nkeyring.delete_password('keychain-bridge-test', 'test')\nprint('Keychain health: OK')\n\"\n\nIf this fails, see Diagnose Issues below."
      },
      {
        "title": "Migrate Secrets",
        "body": "Migrate plaintext secret files to macOS Keychain. The migration tool:\n\nAuto-detects all Python versions on the system\nInjects each secret from ALL detected Python binaries (required for ACL coverage)\nVerifies the round-trip read\nOptionally deletes the original file\n\npython3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot --dry-run\n# Remove --dry-run to actually migrate\npython3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\nAfter migration, secrets fall into two groups:"
      },
      {
        "title": "Group A — Keychain Only",
        "body": "Python scripts read directly via keychain_helper.get_secret(service). No file on disk."
      },
      {
        "title": "Group B — File Bridge",
        "body": "Bash scripts cannot reliably use Python keyring as a subprocess (see Known Issues). For these, a boot-time bridge script populates files from the keychain:\n\n# Add to your LaunchAgent or startup script:\nbash SKILL_DIR/scripts/populate_secrets.sh\n\nThis reads each Group B secret from keychain and writes it to a chmod 600 file that bash scripts can cat."
      },
      {
        "title": "From Python",
        "body": "import sys, os\nsys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\nfrom keychain_helper import get_secret\n\ntoken = get_secret(\"my-service-name\")\n\nThe helper tries keychain first, falls back to file read."
      },
      {
        "title": "From Bash (via Group B file)",
        "body": "MY_SECRET=$(cat ~/.openclaw/secrets/my-service-name)\n\nEnsure the service is listed in populate_secrets.sh so the file is populated at boot."
      },
      {
        "title": "From Bash (via CLI helper — interactive only)",
        "body": "# Works from terminal, but HANGS from LaunchAgent bash scripts\nMY_SECRET=$(python3 path/to/get_secret.py my-service-name)"
      },
      {
        "title": "Write a Secret",
        "body": "Critical: Inject from ALL Python versions on the system. Keychain ACLs are per-binary — an item created by Python 3.9 cannot be read by Python 3.14 unless both binaries are in the ACL.\n\n# Detect Python versions\nPYTHONS=()\n[ -x /usr/bin/python3 ] && PYTHONS+=(/usr/bin/python3)\n[ -x /opt/homebrew/opt/python@3.14/bin/python3.14 ] && PYTHONS+=(/opt/homebrew/opt/python@3.14/bin/python3.14)\n\n# Inject from each\nfor py in \"${PYTHONS[@]}\"; do\n    $py -c \"import keyring; keyring.set_password('SERVICE', 'ACCOUNT', 'VALUE')\"\ndone\n\nOr use the migration tool for batch operations."
      },
      {
        "title": "Audit for Leaks",
        "body": "Check for unexpected plaintext secret files and verify keychain health:\n\npython3 SKILL_DIR/scripts/audit_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\nReports:\n\nUnexpected files in the secrets directory (potential leaks)\nKeychain items that exist but can't be read (ACL issues)\nFiles that exist but aren't in keychain (unmigrated)\nKeychain library installation status per Python version"
      },
      {
        "title": "security find-generic-password -w hangs",
        "body": "macOS Tahoe 26.x regression. The security CLI hangs indefinitely (or returns exit code 36) when reading keychain items, even after security unlock-keychain. This affects ALL CLI-based keychain reads.\n\nFix: Use Python keyring library instead. It uses the Security framework C API via ctypes, bypassing the broken CLI entirely."
      },
      {
        "title": "Python keyring returns None or raises errSecInteractionNotAllowed (-25308)",
        "body": "This happens when running from an SSH session. The keychain requires a GUI session (SecurityAgent) context.\n\nFix (recommended): Use the Group B file-bridge pattern. Write secrets from a GUI session (LaunchAgent or VNC Terminal), then read from chmod 600 files in SSH.\n\nFix (SSH write — ctypes unlock): The security unlock-keychain -p CLI command is also broken on Tahoe (returns \"incorrect passphrase\" with correct password). Use the Security framework C API via ctypes instead. The unlock + set + verify must happen in a single Python process — the unlock does not persist across invocations:\n\npython3 << 'PYEOF'\nimport ctypes, ctypes.util, keyring\n\n# Unlock via Security framework (bypasses broken security CLI)\nSecurity = ctypes.cdll.LoadLibrary(ctypes.util.find_library(\"Security\"))\nkeychain = ctypes.c_void_p()\npath = b\"/Users/USERNAME/Library/Keychains/login.keychain-db\"\nSecurity.SecKeychainOpen(path, ctypes.byref(keychain))\npw = b\"YOUR_LOGIN_PASSWORD\"\nSecurity.SecKeychainUnlock(keychain, ctypes.c_uint32(len(pw)), pw, ctypes.c_bool(True))\n\n# Now keyring works — but ONLY within this same process\nkeyring.set_password(\"SERVICE\", \"ACCOUNT\", \"VALUE\")\nprint(\"OK\" if keyring.get_password(\"SERVICE\", \"ACCOUNT\") else \"FAIL\")\nPYEOF\n\nCaveats of ctypes unlock:\n\nUnlock is process-scoped — a second python3 invocation starts locked again\nOnly /usr/bin/python3 (Apple system Python) can write after ctypes unlock; Homebrew Pythons (3.12, 3.14) still get -25308 even in the same process\nFor multi-Python ACL coverage, write from /usr/bin/python3 first, then inject from other Pythons in a VNC Terminal session (GUI context)\nIf you need SSH-only access to the secret after writing, create a Group B bridge file in the same process:\n\n# After keyring.set_password() succeeds in the same process:\nimport os\nval = keyring.get_password(\"SERVICE\", \"ACCOUNT\")\nos.makedirs(os.path.expanduser(\"~/.my-app/secrets\"), exist_ok=True)\npath = os.path.expanduser(\"~/.my-app/secrets/SERVICE\")\nwith open(path, \"w\") as f:\n    f.write(val)\nos.chmod(path, 0o600)"
      },
      {
        "title": "Python keyring hangs when called from bash LaunchAgent",
        "body": "Novel finding (macOS Tahoe 26.x). When a bash script is the LaunchAgent program and spawns python3 get_secret.py as a subprocess, the Python process hangs indefinitely. The SecurityAgent session attachment is lost in the bash-to-python subprocess transition.\n\nFix: Use the Group B file-bridge pattern. Have a Python-native process populate files at boot, then bash scripts read from files.\n\nAlternatively, make Python the direct LaunchAgent program (not a subprocess of bash)."
      },
      {
        "title": "Different Python versions can't read each other's items",
        "body": "Keychain ACLs are per-binary. An item created by /usr/bin/python3 (Python 3.9) has an ACL entry only for that binary. /opt/homebrew/bin/python3.14 is a different binary and gets access denied.\n\nFix: Inject from both Python versions:\n\n# Read from working version, write via target version\nimport subprocess, keyring\nvalue = keyring.get_password(\"service\", \"account\")\nsubprocess.run([\"/opt/homebrew/bin/python3.14\", \"-c\",\n    f\"import keyring; keyring.set_password('service', 'account', '{value}')\"])\n\nOr use migrate_secrets.py which handles this automatically."
      },
      {
        "title": "keyring not installed for a Python version",
        "body": "Each Python binary has its own site-packages. pip3 install keyring only installs for one.\n\n# Check which Python pip3 targets\npip3 --version\n# Install for system Python\n/usr/bin/python3 -m pip install keyring\n# Install for Homebrew Python\n/opt/homebrew/opt/python@3.14/bin/python3.14 -m pip install --break-system-packages keyring"
      },
      {
        "title": "Architecture Reference",
        "body": "┌─────────────────────┐\n                    │   macOS Keychain     │\n                    │  (login keychain)    │\n                    └──────────┬──────────┘\n                               │\n              ┌────────────────┼────────────────┐\n              │                │                │\n    ┌─────────▼─────────┐     │     ┌──────────▼──────────┐\n    │   Group A          │     │     │   Group B            │\n    │   (keychain only)  │     │     │   (file bridge)      │\n    │                    │     │     │                      │\n    │ Python scripts     │     │     │ populate_secrets.sh  │\n    │ import keychain_   │     │     │ runs at boot →       │\n    │ helper.get_secret()│     │     │ writes chmod 600     │\n    │                    │     │     │ files for bash       │\n    └────────────────────┘     │     └──────────────────────┘\n                               │\n                    ┌──────────▼──────────┐\n                    │   Fallback           │\n                    │   get_secret() tries │\n                    │   keychain first,    │\n                    │   then file read     │\n                    └─────────────────────┘"
      },
      {
        "title": "When to use Group A",
        "body": "The consumer is a Python script\nThe script runs as a LaunchAgent (or from terminal)\nThe script is NOT spawned as a subprocess from a bash LaunchAgent"
      },
      {
        "title": "When to use Group B",
        "body": "The consumer is a bash script\nThe bash script runs as a LaunchAgent\nThe secret is referenced by a config file that expects file:secrets/ paths"
      },
      {
        "title": "Known Issues (macOS Tahoe 26.x)",
        "body": "security CLI broken across the board: find-generic-password -w hangs or exits 36. unlock-keychain -p returns \"incorrect passphrase\" with correct password. show-keychain-info exits 36. The entire security CLI is unreliable on Tahoe — use Python keyring (Group A) or ctypes Security framework for all keychain operations.\nKeychain ACL per-binary: Must inject from every Python version that will read the item.\nBash subprocess loses SecurityAgent: bash LaunchAgent → python3 subprocess hangs. Use Group B file bridge.\nSSH sessions lack GUI context: Keychain reads/writes fail with -25308. Use ctypes SecKeychainUnlock in the same Python process (see Diagnose Issues), or use Group B file bridge. The ctypes unlock is process-scoped — it does not persist across separate command invocations.\nkeyring must be installed per-Python: Each binary's site-packages is independent.\nHomebrew Python ignores ctypes unlock: After SecKeychainUnlock via ctypes, /usr/bin/python3 (Apple system Python 3.9) can read/write via keyring, but Homebrew Pythons (3.12, 3.14) still get -25308. Root cause unknown — may be entitlement or codesigning difference. Workaround: write from /usr/bin/python3, then inject from Homebrew Pythons in a GUI session (VNC Terminal or LaunchAgent).\n\nThese issues are specific to macOS Tahoe 26.x (macOS 26). Earlier versions (Sonoma 14, Sequoia 15) may not exhibit all of them, but the Group A/B architecture is safe on all versions."
      },
      {
        "title": "External Endpoints",
        "body": "None. This skill makes zero network requests. All operations are local to the macOS Keychain and filesystem."
      },
      {
        "title": "Security & Privacy",
        "body": "All operations execute locally against the macOS login keychain\nNo telemetry, analytics, or usage tracking\nNo data leaves the machine under any circumstances\nScripts request no network permissions\nSecrets are only read from and written to the local keychain or chmod 600 files\nMigration tool never logs or displays secret values"
      },
      {
        "title": "Trust Statement",
        "body": "All code is open for inspection — no obfuscation, no minification, no compiled binaries. The skill operates exclusively on the local macOS Keychain and filesystem. Built and tested on a production Mac Mini M4 Pro deployment running OpenClaw 24/7 with 12+ API keys and 25 automated scripts."
      }
    ],
    "body": "Keychain Bridge\nTrigger Phrases\n\"migrate secrets to keychain\" / \"move secrets\"\n\"check keychain health\" / \"keychain status\"\n\"audit secrets\" / \"check for leaks\"\n\"read secret\" / \"get API key\"\n\"store secret\" / \"write to keychain\"\n\"keychain not working\" / \"security find-generic-password hangs\"\nExample Usage\nUser: \"Migrate my secrets to the keychain\"\nAction: python3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot --dry-run\n\nUser: \"Check if the keychain bridge is healthy\"\nAction: Run keychain health check (test write/read/delete cycle)\n\nUser: \"Audit for plaintext secret leaks\"\nAction: python3 SKILL_DIR/scripts/audit_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\n\nManage secrets via macOS Keychain instead of plaintext files. Eliminates plaintext credential storage while maintaining compatibility with bash-based tools through a file-bridge architecture.\n\nPrerequisites\n\nThe keyring Python library must be installed for each Python version that will access secrets:\n\npip3 install keyring\n# If multiple Python versions exist (common on macOS):\n/usr/bin/python3 -m pip install keyring\n/opt/homebrew/opt/python@3.14/bin/python3.14 -m pip install --break-system-packages keyring\n\nCheck Keychain Health\n\nVerify the keychain bridge is working correctly:\n\npython3 -c \"\nimport keyring\n# Test write\nkeyring.set_password('keychain-bridge-test', 'test', 'hello')\n# Test read\nval = keyring.get_password('keychain-bridge-test', 'test')\nassert val == 'hello', f'Read back {val!r}, expected hello'\n# Cleanup\nkeyring.delete_password('keychain-bridge-test', 'test')\nprint('Keychain health: OK')\n\"\n\n\nIf this fails, see Diagnose Issues below.\n\nMigrate Secrets\n\nMigrate plaintext secret files to macOS Keychain. The migration tool:\n\nAuto-detects all Python versions on the system\nInjects each secret from ALL detected Python binaries (required for ACL coverage)\nVerifies the round-trip read\nOptionally deletes the original file\npython3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot --dry-run\n# Remove --dry-run to actually migrate\npython3 SKILL_DIR/scripts/migrate_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\n\nAfter migration, secrets fall into two groups:\n\nGroup A — Keychain Only\n\nPython scripts read directly via keychain_helper.get_secret(service). No file on disk.\n\nGroup B — File Bridge\n\nBash scripts cannot reliably use Python keyring as a subprocess (see Known Issues). For these, a boot-time bridge script populates files from the keychain:\n\n# Add to your LaunchAgent or startup script:\nbash SKILL_DIR/scripts/populate_secrets.sh\n\n\nThis reads each Group B secret from keychain and writes it to a chmod 600 file that bash scripts can cat.\n\nRead a Secret\nFrom Python\nimport sys, os\nsys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))\nfrom keychain_helper import get_secret\n\ntoken = get_secret(\"my-service-name\")\n\n\nThe helper tries keychain first, falls back to file read.\n\nFrom Bash (via Group B file)\nMY_SECRET=$(cat ~/.openclaw/secrets/my-service-name)\n\n\nEnsure the service is listed in populate_secrets.sh so the file is populated at boot.\n\nFrom Bash (via CLI helper — interactive only)\n# Works from terminal, but HANGS from LaunchAgent bash scripts\nMY_SECRET=$(python3 path/to/get_secret.py my-service-name)\n\nWrite a Secret\n\nCritical: Inject from ALL Python versions on the system. Keychain ACLs are per-binary — an item created by Python 3.9 cannot be read by Python 3.14 unless both binaries are in the ACL.\n\n# Detect Python versions\nPYTHONS=()\n[ -x /usr/bin/python3 ] && PYTHONS+=(/usr/bin/python3)\n[ -x /opt/homebrew/opt/python@3.14/bin/python3.14 ] && PYTHONS+=(/opt/homebrew/opt/python@3.14/bin/python3.14)\n\n# Inject from each\nfor py in \"${PYTHONS[@]}\"; do\n    $py -c \"import keyring; keyring.set_password('SERVICE', 'ACCOUNT', 'VALUE')\"\ndone\n\n\nOr use the migration tool for batch operations.\n\nAudit for Leaks\n\nCheck for unexpected plaintext secret files and verify keychain health:\n\npython3 SKILL_DIR/scripts/audit_secrets.py --dir ~/.openclaw/secrets/ --account moltbot\n\n\nReports:\n\nUnexpected files in the secrets directory (potential leaks)\nKeychain items that exist but can't be read (ACL issues)\nFiles that exist but aren't in keychain (unmigrated)\nKeychain library installation status per Python version\nDiagnose Issues\nsecurity find-generic-password -w hangs\n\nmacOS Tahoe 26.x regression. The security CLI hangs indefinitely (or returns exit code 36) when reading keychain items, even after security unlock-keychain. This affects ALL CLI-based keychain reads.\n\nFix: Use Python keyring library instead. It uses the Security framework C API via ctypes, bypassing the broken CLI entirely.\n\nPython keyring returns None or raises errSecInteractionNotAllowed (-25308)\n\nThis happens when running from an SSH session. The keychain requires a GUI session (SecurityAgent) context.\n\nFix (recommended): Use the Group B file-bridge pattern. Write secrets from a GUI session (LaunchAgent or VNC Terminal), then read from chmod 600 files in SSH.\n\nFix (SSH write — ctypes unlock): The security unlock-keychain -p CLI command is also broken on Tahoe (returns \"incorrect passphrase\" with correct password). Use the Security framework C API via ctypes instead. The unlock + set + verify must happen in a single Python process — the unlock does not persist across invocations:\n\npython3 << 'PYEOF'\nimport ctypes, ctypes.util, keyring\n\n# Unlock via Security framework (bypasses broken security CLI)\nSecurity = ctypes.cdll.LoadLibrary(ctypes.util.find_library(\"Security\"))\nkeychain = ctypes.c_void_p()\npath = b\"/Users/USERNAME/Library/Keychains/login.keychain-db\"\nSecurity.SecKeychainOpen(path, ctypes.byref(keychain))\npw = b\"YOUR_LOGIN_PASSWORD\"\nSecurity.SecKeychainUnlock(keychain, ctypes.c_uint32(len(pw)), pw, ctypes.c_bool(True))\n\n# Now keyring works — but ONLY within this same process\nkeyring.set_password(\"SERVICE\", \"ACCOUNT\", \"VALUE\")\nprint(\"OK\" if keyring.get_password(\"SERVICE\", \"ACCOUNT\") else \"FAIL\")\nPYEOF\n\n\nCaveats of ctypes unlock:\n\nUnlock is process-scoped — a second python3 invocation starts locked again\nOnly /usr/bin/python3 (Apple system Python) can write after ctypes unlock; Homebrew Pythons (3.12, 3.14) still get -25308 even in the same process\nFor multi-Python ACL coverage, write from /usr/bin/python3 first, then inject from other Pythons in a VNC Terminal session (GUI context)\nIf you need SSH-only access to the secret after writing, create a Group B bridge file in the same process:\n# After keyring.set_password() succeeds in the same process:\nimport os\nval = keyring.get_password(\"SERVICE\", \"ACCOUNT\")\nos.makedirs(os.path.expanduser(\"~/.my-app/secrets\"), exist_ok=True)\npath = os.path.expanduser(\"~/.my-app/secrets/SERVICE\")\nwith open(path, \"w\") as f:\n    f.write(val)\nos.chmod(path, 0o600)\n\nPython keyring hangs when called from bash LaunchAgent\n\nNovel finding (macOS Tahoe 26.x). When a bash script is the LaunchAgent program and spawns python3 get_secret.py as a subprocess, the Python process hangs indefinitely. The SecurityAgent session attachment is lost in the bash-to-python subprocess transition.\n\nFix: Use the Group B file-bridge pattern. Have a Python-native process populate files at boot, then bash scripts read from files.\n\nAlternatively, make Python the direct LaunchAgent program (not a subprocess of bash).\n\nDifferent Python versions can't read each other's items\n\nKeychain ACLs are per-binary. An item created by /usr/bin/python3 (Python 3.9) has an ACL entry only for that binary. /opt/homebrew/bin/python3.14 is a different binary and gets access denied.\n\nFix: Inject from both Python versions:\n\n# Read from working version, write via target version\nimport subprocess, keyring\nvalue = keyring.get_password(\"service\", \"account\")\nsubprocess.run([\"/opt/homebrew/bin/python3.14\", \"-c\",\n    f\"import keyring; keyring.set_password('service', 'account', '{value}')\"])\n\n\nOr use migrate_secrets.py which handles this automatically.\n\nkeyring not installed for a Python version\n\nEach Python binary has its own site-packages. pip3 install keyring only installs for one.\n\n# Check which Python pip3 targets\npip3 --version\n# Install for system Python\n/usr/bin/python3 -m pip install keyring\n# Install for Homebrew Python\n/opt/homebrew/opt/python@3.14/bin/python3.14 -m pip install --break-system-packages keyring\n\nArchitecture Reference\n                    ┌─────────────────────┐\n                    │   macOS Keychain     │\n                    │  (login keychain)    │\n                    └──────────┬──────────┘\n                               │\n              ┌────────────────┼────────────────┐\n              │                │                │\n    ┌─────────▼─────────┐     │     ┌──────────▼──────────┐\n    │   Group A          │     │     │   Group B            │\n    │   (keychain only)  │     │     │   (file bridge)      │\n    │                    │     │     │                      │\n    │ Python scripts     │     │     │ populate_secrets.sh  │\n    │ import keychain_   │     │     │ runs at boot →       │\n    │ helper.get_secret()│     │     │ writes chmod 600     │\n    │                    │     │     │ files for bash       │\n    └────────────────────┘     │     └──────────────────────┘\n                               │\n                    ┌──────────▼──────────┐\n                    │   Fallback           │\n                    │   get_secret() tries │\n                    │   keychain first,    │\n                    │   then file read     │\n                    └─────────────────────┘\n\nWhen to use Group A\nThe consumer is a Python script\nThe script runs as a LaunchAgent (or from terminal)\nThe script is NOT spawned as a subprocess from a bash LaunchAgent\nWhen to use Group B\nThe consumer is a bash script\nThe bash script runs as a LaunchAgent\nThe secret is referenced by a config file that expects file:secrets/ paths\nKnown Issues (macOS Tahoe 26.x)\nsecurity CLI broken across the board: find-generic-password -w hangs or exits 36. unlock-keychain -p returns \"incorrect passphrase\" with correct password. show-keychain-info exits 36. The entire security CLI is unreliable on Tahoe — use Python keyring (Group A) or ctypes Security framework for all keychain operations.\nKeychain ACL per-binary: Must inject from every Python version that will read the item.\nBash subprocess loses SecurityAgent: bash LaunchAgent → python3 subprocess hangs. Use Group B file bridge.\nSSH sessions lack GUI context: Keychain reads/writes fail with -25308. Use ctypes SecKeychainUnlock in the same Python process (see Diagnose Issues), or use Group B file bridge. The ctypes unlock is process-scoped — it does not persist across separate command invocations.\nkeyring must be installed per-Python: Each binary's site-packages is independent.\nHomebrew Python ignores ctypes unlock: After SecKeychainUnlock via ctypes, /usr/bin/python3 (Apple system Python 3.9) can read/write via keyring, but Homebrew Pythons (3.12, 3.14) still get -25308. Root cause unknown — may be entitlement or codesigning difference. Workaround: write from /usr/bin/python3, then inject from Homebrew Pythons in a GUI session (VNC Terminal or LaunchAgent).\n\nThese issues are specific to macOS Tahoe 26.x (macOS 26). Earlier versions (Sonoma 14, Sequoia 15) may not exhibit all of them, but the Group A/B architecture is safe on all versions.\n\nExternal Endpoints\n\nNone. This skill makes zero network requests. All operations are local to the macOS Keychain and filesystem.\n\nSecurity & Privacy\nAll operations execute locally against the macOS login keychain\nNo telemetry, analytics, or usage tracking\nNo data leaves the machine under any circumstances\nScripts request no network permissions\nSecrets are only read from and written to the local keychain or chmod 600 files\nMigration tool never logs or displays secret values\nTrust Statement\n\nAll code is open for inspection — no obfuscation, no minification, no compiled binaries. The skill operates exclusively on the local macOS Keychain and filesystem. Built and tested on a production Mac Mini M4 Pro deployment running OpenClaw 24/7 with 12+ API keys and 25 automated scripts."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Euda1mon1a/keychain-bridge",
    "publisherUrl": "https://clawhub.ai/Euda1mon1a/keychain-bridge",
    "owner": "Euda1mon1a",
    "version": "1.1.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/keychain-bridge",
    "downloadUrl": "https://openagent3.xyz/downloads/keychain-bridge",
    "agentUrl": "https://openagent3.xyz/skills/keychain-bridge/agent",
    "manifestUrl": "https://openagent3.xyz/skills/keychain-bridge/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/keychain-bridge/agent.md"
  }
}