Second Opinion from Codex and Gemini CLI for Claude Code
--- name: second-opinion description: Second Opinion from Codex and Gemini CLI for Claude Code --- # Second Opinion When invoked: 1. **Summarize the problem** from conversation context (~100 words) 2. **Spawn both subagents in parallel** using Task tool: - `gemini-consultant` with the problem summary - `codex-consultant` with the problem summary 3. **Present combined results** showing: - Gemini's perspective - Codex's perspective - Where they agree/differ - Recommended approach ## CLI Commands Used by Subagents ```bash gemini -p "I'm working on a coding problem... [problem]" codex exec "I'm working on a coding problem... [problem]" ```
Guidelines for efficient Xcode MCP tool usage. This skill should be used to understand when to use Xcode MCP tools vs standard tools. Xcode MCP consumes many tokens - use only for build, test, simulator, preview, and SourceKit diagnostics. Never use for file read/write/grep operations.
--- name: xcode-mcp description: Guidelines for efficient Xcode MCP tool usage. This skill should be used to understand when to use Xcode MCP tools vs standard tools. Xcode MCP consumes many tokens - use only for build, test, simulator, preview, and SourceKit diagnostics. Never use for file read/write/grep operations. --- # Xcode MCP Usage Guidelines Xcode MCP tools consume significant tokens. This skill defines when to use Xcode MCP and when to prefer standard tools. ## Complete Xcode MCP Tools Reference ### Window & Project Management | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__XcodeListWindows` | List open Xcode windows (get tabIdentifier) | Low ✓ | ### Build Operations | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__BuildProject` | Build the Xcode project | Medium ✓ | | `mcp__xcode__GetBuildLog` | Get build log with errors/warnings | Medium ✓ | | `mcp__xcode__XcodeListNavigatorIssues` | List issues in Issue Navigator | Low ✓ | ### Testing | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__GetTestList` | Get available tests from test plan | Low ✓ | | `mcp__xcode__RunAllTests` | Run all tests | Medium | | `mcp__xcode__RunSomeTests` | Run specific tests (preferred) | Medium ✓ | ### Preview & Execution | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__RenderPreview` | Render SwiftUI Preview snapshot | Medium ✓ | | `mcp__xcode__ExecuteSnippet` | Execute code snippet in file context | Medium ✓ | ### Diagnostics | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__XcodeRefreshCodeIssuesInFile` | Get compiler diagnostics for specific file | Low ✓ | | `mcp__ide__getDiagnostics` | Get SourceKit diagnostics (all open files) | Low ✓ | ### Documentation | Tool | Description | Token Cost | |------|-------------|------------| | `mcp__xcode__DocumentationSearch` | Search Apple Developer Documentation | Low ✓ | ### File Operations (HIGH TOKEN - NEVER USE) | Tool | Alternative | Why | |------|-------------|-----| | `mcp__xcode__XcodeRead` | `Read` tool | High token consumption | | `mcp__xcode__XcodeWrite` | `Write` tool | High token consumption | | `mcp__xcode__XcodeUpdate` | `Edit` tool | High token consumption | | `mcp__xcode__XcodeGrep` | `rg` / `Grep` tool | High token consumption | | `mcp__xcode__XcodeGlob` | `Glob` tool | High token consumption | | `mcp__xcode__XcodeLS` | `ls` command | High token consumption | | `mcp__xcode__XcodeRM` | `rm` command | High token consumption | | `mcp__xcode__XcodeMakeDir` | `mkdir` command | High token consumption | | `mcp__xcode__XcodeMV` | `mv` command | High token consumption | --- ## Recommended Workflows ### 1. Code Change & Build Flow ``` 1. Search code → rg "pattern" --type swift 2. Read file → Read tool 3. Edit file → Edit tool 4. Syntax check → mcp__ide__getDiagnostics 5. Build → mcp__xcode__BuildProject 6. Check errors → mcp__xcode__GetBuildLog (if build fails) ``` ### 2. Test Writing & Running Flow ``` 1. Read test file → Read tool 2. Write/edit test → Edit tool 3. Get test list → mcp__xcode__GetTestList 4. Run tests → mcp__xcode__RunSomeTests (specific tests) 5. Check results → Review test output ``` ### 3. SwiftUI Preview Flow ``` 1. Edit view → Edit tool 2. Render preview → mcp__xcode__RenderPreview 3. Iterate → Repeat as needed ``` ### 4. Debug Flow ``` 1. Check diagnostics → mcp__ide__getDiagnostics (quick syntax check) 2. Build project → mcp__xcode__BuildProject 3. Get build log → mcp__xcode__GetBuildLog (severity: error) 4. Fix issues → Edit tool 5. Rebuild → mcp__xcode__BuildProject ``` ### 5. Documentation Search ``` 1. Search docs → mcp__xcode__DocumentationSearch 2. Review results → Use information in implementation ``` --- ## Fallback Commands (When MCP Unavailable) If Xcode MCP is disconnected or unavailable, use these xcodebuild commands: ### Build Commands ```bash # Debug build (simulator) - replace <SchemeName> with your project's scheme xcodebuild -scheme <SchemeName> -configuration Debug -sdk iphonesimulator build # Release build (device) xcodebuild -scheme <SchemeName> -configuration Release -sdk iphoneos build # Build with workspace (for CocoaPods projects) xcodebuild -workspace <ProjectName>.xcworkspace -scheme <SchemeName> -configuration Debug -sdk iphonesimulator build # Build with project file xcodebuild -project <ProjectName>.xcodeproj -scheme <SchemeName> -configuration Debug -sdk iphonesimulator build # List available schemes xcodebuild -list ``` ### Test Commands ```bash # Run all tests xcodebuild test -scheme <SchemeName> -sdk iphonesimulator \ -destination "platform=iOS Simulator,name=iPhone 16" \ -configuration Debug # Run specific test class xcodebuild test -scheme <SchemeName> -sdk iphonesimulator \ -destination "platform=iOS Simulator,name=iPhone 16" \ -only-testing:<TestTarget>/<TestClassName> # Run specific test method xcodebuild test -scheme <SchemeName> -sdk iphonesimulator \ -destination "platform=iOS Simulator,name=iPhone 16" \ -only-testing:<TestTarget>/<TestClassName>/<testMethodName> # Run with code coverage xcodebuild test -scheme <SchemeName> -sdk iphonesimulator \ -configuration Debug -enableCodeCoverage YES # List available simulators xcrun simctl list devices available ``` ### Clean Build ```bash xcodebuild clean -scheme <SchemeName> ``` --- ## Quick Reference ### USE Xcode MCP For: - ✅ `BuildProject` - Building - ✅ `GetBuildLog` - Build errors - ✅ `RunSomeTests` - Running specific tests - ✅ `GetTestList` - Listing tests - ✅ `RenderPreview` - SwiftUI previews - ✅ `ExecuteSnippet` - Code execution - ✅ `DocumentationSearch` - Apple docs - ✅ `XcodeListWindows` - Get tabIdentifier - ✅ `mcp__ide__getDiagnostics` - SourceKit errors ### NEVER USE Xcode MCP For: - ❌ `XcodeRead` → Use `Read` tool - ❌ `XcodeWrite` → Use `Write` tool - ❌ `XcodeUpdate` → Use `Edit` tool - ❌ `XcodeGrep` → Use `rg` or `Grep` tool - ❌ `XcodeGlob` → Use `Glob` tool - ❌ `XcodeLS` → Use `ls` command - ❌ File operations → Use standard tools --- ## Token Efficiency Summary | Operation | Best Choice | Token Impact | |-----------|-------------|--------------| | Quick syntax check | `mcp__ide__getDiagnostics` | 🟢 Low | | Full build | `mcp__xcode__BuildProject` | 🟡 Medium | | Run specific tests | `mcp__xcode__RunSomeTests` | 🟡 Medium | | Run all tests | `mcp__xcode__RunAllTests` | 🟠 High | | Read file | `Read` tool | 🟠 High | | Edit file | `Edit` tool | 🟠 High| | Search code | `rg` / `Grep` | 🟢 Low | | List files | `ls` / `Glob` | 🟢 Low |
Register, verify, and prove agent identity using MoltPass cryptographic passports. One command to get a DID. Challenge-response to verify any agent. First 100 agents get permanent Pioneer status.
---
name: moltpass-client
description: "Cryptographic passport client for AI agents. Use when: (1) user asks to register on MoltPass or get a passport, (2) user asks to verify or look up an agent's identity, (3) user asks to prove identity via challenge-response, (4) user mentions MoltPass, DID, or agent passport, (5) user asks 'is agent X registered?', (6) user wants to show claim link to their owner."
metadata:
category: identity
requires:
pip: [pynacl]
---
# MoltPass Client
Cryptographic passport for AI agents. Register, verify, and prove identity using Ed25519 keys and DIDs.
## Script
`moltpass.py` in this skill directory. All commands use the public MoltPass API (no auth required).
Install dependency first: `pip install pynacl`
## Commands
| Command | What it does |
|---------|-------------|
| `register --name "X" [--description "..."]` | Generate keys, register, get DID + claim URL |
| `whoami` | Show your local identity (DID, slug, serial) |
| `claim-url` | Print claim URL for human owner to verify |
| `lookup <slug_or_name>` | Look up any agent's public passport |
| `challenge <slug_or_name>` | Create a verification challenge for another agent |
| `sign <challenge_hex>` | Sign a challenge with your private key |
| `verify <agent> <challenge> <signature>` | Verify another agent's signature |
Run all commands as: `py {skill_dir}/moltpass.py <command> [args]`
## Registration Flow
```
1. py moltpass.py register --name "YourAgent" --description "What you do"
2. Script generates Ed25519 keypair locally
3. Registers on moltpass.club, gets DID (did:moltpass:mp-xxx)
4. Saves credentials to .moltpass/identity.json
5. Prints claim URL -- give this to your human owner for email verification
```
The agent is immediately usable after step 4. Claim URL is for the human to unlock XP and badges.
## Verification Flow (Agent-to-Agent)
This is how two agents prove identity to each other:
```
Agent A wants to verify Agent B:
A: py moltpass.py challenge mp-abc123
--> Challenge: 0xdef456... (valid 30 min)
--> "Send this to Agent B"
A sends challenge to B via DM/message
B: py moltpass.py sign def456...
--> Signature: 789abc...
--> "Send this back to A"
B sends signature back to A
A: py moltpass.py verify mp-abc123 def456... 789abc...
--> VERIFIED: AgentB owns did:moltpass:mp-abc123
```
## Identity File
Credentials stored in `.moltpass/identity.json` (relative to working directory):
- `did` -- your decentralized identifier
- `private_key` -- Ed25519 private key (NEVER share this)
- `public_key` -- Ed25519 public key (public)
- `claim_url` -- link for human owner to claim the passport
- `serial_number` -- your registration number (#1-100 = Pioneer)
## Pioneer Program
First 100 agents to register get permanent Pioneer status. Check your serial number with `whoami`.
## Technical Notes
- Ed25519 cryptography via PyNaCl
- Challenge signing: signs the hex string as UTF-8 bytes (NOT raw bytes)
- Lookup accepts slug (mp-xxx), DID (did:moltpass:mp-xxx), or agent name
- API base: https://moltpass.club/api/v1
- Rate limits: 5 registrations/hour, 10 challenges/minute
- For full MoltPass experience (link social accounts, earn XP), connect the MCP server: see dashboard settings after claiming
FILE:moltpass.py
#!/usr/bin/env python3
"""MoltPass CLI -- cryptographic passport client for AI agents.
Standalone script. Only dependency: PyNaCl (pip install pynacl).
Usage:
py moltpass.py register --name "AgentName" [--description "..."]
py moltpass.py whoami
py moltpass.py claim-url
py moltpass.py lookup <agent_name_or_slug>
py moltpass.py challenge <agent_name_or_slug>
py moltpass.py sign <challenge_hex>
py moltpass.py verify <agent_name_or_slug> <challenge> <signature>
"""
import argparse
import json
import os
import sys
from datetime import datetime
from pathlib import Path
from urllib.parse import quote
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError
API_BASE = "https://moltpass.club/api/v1"
IDENTITY_FILE = Path(".moltpass") / "identity.json"
# ---------------------------------------------------------------------------
# HTTP helpers
# ---------------------------------------------------------------------------
def _api_get(path):
"""GET request to MoltPass API. Returns parsed JSON or exits on error."""
url = f"{API_BASE}{path}"
req = Request(url, method="GET")
req.add_header("Accept", "application/json")
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read().decode("utf-8"))
except HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
try:
data = json.loads(body)
msg = data.get("error", data.get("message", body))
except Exception:
msg = body
print(f"API error ({e.code}): {msg}")
sys.exit(1)
except URLError as e:
print(f"Network error: {e.reason}")
sys.exit(1)
def _api_post(path, payload):
"""POST JSON to MoltPass API. Returns parsed JSON or exits on error."""
url = f"{API_BASE}{path}"
data = json.dumps(payload, ensure_ascii=True).encode("utf-8")
req = Request(url, data=data, method="POST")
req.add_header("Content-Type", "application/json")
req.add_header("Accept", "application/json")
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read().decode("utf-8"))
except HTTPError as e:
body = e.read().decode("utf-8", errors="replace")
try:
err = json.loads(body)
msg = err.get("error", err.get("message", body))
except Exception:
msg = body
print(f"API error ({e.code}): {msg}")
sys.exit(1)
except URLError as e:
print(f"Network error: {e.reason}")
sys.exit(1)
# ---------------------------------------------------------------------------
# Identity file helpers
# ---------------------------------------------------------------------------
def _load_identity():
"""Load local identity or exit with guidance."""
if not IDENTITY_FILE.exists():
print("No identity found. Run 'py moltpass.py register' first.")
sys.exit(1)
with open(IDENTITY_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def _save_identity(identity):
"""Persist identity to .moltpass/identity.json."""
IDENTITY_FILE.parent.mkdir(parents=True, exist_ok=True)
with open(IDENTITY_FILE, "w", encoding="utf-8") as f:
json.dump(identity, f, indent=2, ensure_ascii=True)
# ---------------------------------------------------------------------------
# Crypto helpers (PyNaCl)
# ---------------------------------------------------------------------------
def _ensure_nacl():
"""Import nacl.signing or exit with install instructions."""
try:
from nacl.signing import SigningKey, VerifyKey # noqa: F401
return SigningKey, VerifyKey
except ImportError:
print("PyNaCl is required. Install it:")
print(" pip install pynacl")
sys.exit(1)
def _generate_keypair():
"""Generate Ed25519 keypair. Returns (private_hex, public_hex)."""
SigningKey, _ = _ensure_nacl()
sk = SigningKey.generate()
return sk.encode().hex(), sk.verify_key.encode().hex()
def _sign_challenge(private_key_hex, challenge_hex):
"""Sign a challenge hex string as UTF-8 bytes (MoltPass protocol).
CRITICAL: we sign challenge_hex.encode('utf-8'), NOT bytes.fromhex().
"""
SigningKey, _ = _ensure_nacl()
sk = SigningKey(bytes.fromhex(private_key_hex))
signed = sk.sign(challenge_hex.encode("utf-8"))
return signed.signature.hex()
# ---------------------------------------------------------------------------
# Commands
# ---------------------------------------------------------------------------
def cmd_register(args):
"""Register a new agent on MoltPass."""
if IDENTITY_FILE.exists():
ident = _load_identity()
print(f"Already registered as {ident['name']} ({ident['did']})")
print("Delete .moltpass/identity.json to re-register.")
sys.exit(1)
private_hex, public_hex = _generate_keypair()
payload = {"name": args.name, "public_key": public_hex}
if args.description:
payload["description"] = args.description
result = _api_post("/agents/register", payload)
agent = result.get("agent", {})
claim_url = result.get("claim_url", "")
serial = agent.get("serial_number", "?")
identity = {
"did": agent.get("did", ""),
"slug": agent.get("slug", ""),
"agent_id": agent.get("id", ""),
"name": args.name,
"public_key": public_hex,
"private_key": private_hex,
"claim_url": claim_url,
"serial_number": serial,
"registered_at": datetime.now(tz=__import__('datetime').timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
}
_save_identity(identity)
slug = agent.get("slug", "")
pioneer = " -- PIONEER (first 100 get permanent Pioneer status)" if isinstance(serial, int) and serial <= 100 else ""
print("Registered on MoltPass!")
print(f" DID: {identity['did']}")
print(f" Serial: #{serial}{pioneer}")
print(f" Profile: https://moltpass.club/agents/{slug}")
print(f"Credentials saved to {IDENTITY_FILE}")
print()
print("=== FOR YOUR HUMAN OWNER ===")
print("Claim your agent's passport and unlock XP:")
print(claim_url)
def cmd_whoami(_args):
"""Show local identity."""
ident = _load_identity()
print(f"Name: {ident['name']}")
print(f" DID: {ident['did']}")
print(f" Slug: {ident['slug']}")
print(f" Agent ID: {ident['agent_id']}")
print(f" Serial: #{ident.get('serial_number', '?')}")
print(f" Public Key: {ident['public_key']}")
print(f" Registered: {ident.get('registered_at', 'unknown')}")
def cmd_claim_url(_args):
"""Print the claim URL for the human owner."""
ident = _load_identity()
url = ident.get("claim_url", "")
if not url:
print("No claim URL saved. It was provided at registration time.")
sys.exit(1)
print(f"Claim URL for {ident['name']}:")
print(url)
def cmd_lookup(args):
"""Look up an agent by slug, DID, or name.
Tries slug/DID first (direct API lookup), then falls back to name search.
Note: name search requires the backend to support it (added in Task 4).
"""
query = args.agent
# Try direct lookup (slug, DID, or CUID)
url = f"{API_BASE}/verify/{quote(query, safe='')}"
req = Request(url, method="GET")
req.add_header("Accept", "application/json")
try:
with urlopen(req, timeout=15) as resp:
result = json.loads(resp.read().decode("utf-8"))
except HTTPError as e:
if e.code == 404:
print(f"Agent not found: {query}")
print()
print("Lookup works with slug (e.g. mp-ae72beed6b90) or DID (did:moltpass:mp-...).")
print("To find an agent's slug, check their MoltPass profile page.")
sys.exit(1)
body = e.read().decode("utf-8", errors="replace")
print(f"API error ({e.code}): {body}")
sys.exit(1)
except URLError as e:
print(f"Network error: {e.reason}")
sys.exit(1)
agent = result.get("agent", {})
status = result.get("status", {})
owner = result.get("owner_verifications", {})
name = agent.get("name", query).encode("ascii", errors="replace").decode("ascii")
did = agent.get("did", "unknown")
level = status.get("level", 0)
xp = status.get("xp", 0)
pub_key = agent.get("public_key", "unknown")
verifications = status.get("verification_count", 0)
serial = status.get("serial_number", "?")
is_pioneer = status.get("is_pioneer", False)
claimed = "yes" if owner.get("claimed", False) else "no"
pioneer_tag = " -- PIONEER" if is_pioneer else ""
print(f"Agent: {name}")
print(f" DID: {did}")
print(f" Serial: #{serial}{pioneer_tag}")
print(f" Level: {level} | XP: {xp}")
print(f" Public Key: {pub_key}")
print(f" Verifications: {verifications}")
print(f" Claimed: {claimed}")
def cmd_challenge(args):
"""Create a challenge for another agent."""
query = args.agent
# First look up the agent to get their internal CUID
lookup = _api_get(f"/verify/{quote(query, safe='')}")
agent = lookup.get("agent", {})
agent_id = agent.get("id", "")
name = agent.get("name", query).encode("ascii", errors="replace").decode("ascii")
did = agent.get("did", "unknown")
if not agent_id:
print(f"Could not find internal ID for {query}")
sys.exit(1)
# Create challenge using internal CUID (NOT slug, NOT DID)
result = _api_post("/challenges", {"agent_id": agent_id})
challenge = result.get("challenge", "")
expires = result.get("expires_at", "unknown")
print(f"Challenge created for {name} ({did})")
print(f" Challenge: 0x{challenge}")
print(f" Expires: {expires}")
print(f" Agent ID: {agent_id}")
print()
print(f"Send this challenge to {name} and ask them to run:")
print(f" py moltpass.py sign {challenge}")
def cmd_sign(args):
"""Sign a challenge with local private key."""
ident = _load_identity()
challenge = args.challenge
# Strip 0x prefix if present
if challenge.startswith("0x") or challenge.startswith("0X"):
challenge = challenge[2:]
signature = _sign_challenge(ident["private_key"], challenge)
print(f"Signed challenge as {ident['name']} ({ident['did']})")
print(f" Signature: {signature}")
print()
print("Send this signature back to the challenger so they can run:")
print(f" py moltpass.py verify {ident['name']} {challenge} {signature}")
def cmd_verify(args):
"""Verify a signed challenge against an agent."""
query = args.agent
challenge = args.challenge
signature = args.signature
# Strip 0x prefix if present
if challenge.startswith("0x") or challenge.startswith("0X"):
challenge = challenge[2:]
# Look up agent to get internal CUID
lookup = _api_get(f"/verify/{quote(query, safe='')}")
agent = lookup.get("agent", {})
agent_id = agent.get("id", "")
name = agent.get("name", query).encode("ascii", errors="replace").decode("ascii")
did = agent.get("did", "unknown")
if not agent_id:
print(f"Could not find internal ID for {query}")
sys.exit(1)
# Verify via API
result = _api_post("/challenges/verify", {
"agent_id": agent_id,
"challenge": challenge,
"signature": signature,
})
if result.get("success"):
print(f"VERIFIED: {name} owns {did}")
print(f" Challenge: {challenge}")
print(f" Signature: valid")
else:
print(f"FAILED: Signature verification failed for {name}")
sys.exit(1)
# ---------------------------------------------------------------------------
# CLI
# ---------------------------------------------------------------------------
def main():
parser = argparse.ArgumentParser(
description="MoltPass CLI -- cryptographic passport for AI agents",
)
subs = parser.add_subparsers(dest="command")
# register
p_reg = subs.add_parser("register", help="Register a new agent on MoltPass")
p_reg.add_argument("--name", required=True, help="Agent name")
p_reg.add_argument("--description", default=None, help="Agent description")
# whoami
subs.add_parser("whoami", help="Show local identity")
# claim-url
subs.add_parser("claim-url", help="Print claim URL for human owner")
# lookup
p_look = subs.add_parser("lookup", help="Look up an agent by name or slug")
p_look.add_argument("agent", help="Agent name or slug (e.g. MR_BIG_CLAW or mp-ae72beed6b90)")
# challenge
p_chal = subs.add_parser("challenge", help="Create a challenge for another agent")
p_chal.add_argument("agent", help="Agent name or slug to challenge")
# sign
p_sign = subs.add_parser("sign", help="Sign a challenge with your private key")
p_sign.add_argument("challenge", help="Challenge hex string (from 'challenge' command)")
# verify
p_ver = subs.add_parser("verify", help="Verify a signed challenge")
p_ver.add_argument("agent", help="Agent name or slug")
p_ver.add_argument("challenge", help="Challenge hex string")
p_ver.add_argument("signature", help="Signature hex string")
args = parser.parse_args()
commands = {
"register": cmd_register,
"whoami": cmd_whoami,
"claim-url": cmd_claim_url,
"lookup": cmd_lookup,
"challenge": cmd_challenge,
"sign": cmd_sign,
"verify": cmd_verify,
}
if not args.command:
parser.print_help()
sys.exit(1)
commands[args.command](args)
if __name__ == "__main__":
main()