Files
tob-joe 40f192b390 let-fate-decide: replace os.urandom with secrets.randbelow (#125)
* galvanize(iter1): replace os.urandom with secrets.randbelow, add tests

Switch card selection from hand-rolled secure_randbelow(os.urandom)
to stdlib secrets.randbelow(). Update all docstrings, SKILL.md, and
README.md references. Add 25-test suite covering deck construction,
shuffle invariants, CLI validation, and migration regression checks.

* Bump version to 1.1.0 and fix stale rejection sampling claim

- Bump version in plugin.json and marketplace.json (1.0.0 → 1.1.0)
- Update SKILL.md to say "via secrets.randbelow()" instead of claiming
  the script itself implements rejection sampling

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix ruff format: collapse line continuation in test assertion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Merge Scott's PR #128 improvements + vivisect fixes

Incorporates unique changes from Scott's closed PR #128:
- Broadened trigger patterns (casual delegation, YOLO, shrug-like
  brevity, expanded Yu-Gi-Oh references) in README.md and SKILL.md
- Improved SKILL.md frontmatter description with casual/playful
  tone guidance and prefer-over-ask-questions-if-underspecified note
- is_reversed() uses secrets.randbits(1) (more idiomatic coin flip)

Additional fixes from vivisect analysis:
- Converted MAJOR_ARCANA, RANKS, SUITS from lists to tuples
  (prevents silent deck corruption if imported as library)
- Added type guard in draw() rejecting non-int/bool inputs
- Added test_constants_are_immutable and test_draw_rejects_non_int

Co-Authored-By: Scott Arciszewski <scott.arciszewski@trailofbits.com>

* let-fate-decide: improve performance by avoiding text-only turns

---------

Co-authored-by: Dan Guido <dan@trailofbits.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Scott Arciszewski <scott.arciszewski@trailofbits.com>
2026-04-01 10:49:10 -04:00
..

let-fate-decide

A Claude Code skill that draws Tarot cards using secrets to inject entropy into vague or underspecified planning decisions.

What It Does

When a prompt is sufficiently ambiguous, or the user explicitly invokes fate, this skill shuffles a full 78-card Tarot deck using cryptographic randomness and draws 4 cards (which may appear reversed). Claude then interprets the spread and uses the reading to inform its approach.

Triggers

  • Vague or ambiguous prompts where multiple reasonable approaches exist
  • "I'm feeling lucky", "let fate decide", "dealer's choice", "surprise me", "whatever you think", "YOLO"
  • Casual delegation ("whatever", "up to you", "your call", "idk", "just do something", "wing it", "I trust you", "doesn't matter", "do what you want", "I don't care", "any approach works", "you pick")
  • Yu-Gi-Oh references ("heart of the cards", "I believe in the heart of the cards", "you've activated my trap card", "it's time to duel")
  • Shrug-like brevity -- very short prompts that fully delegate the decision
  • About to arbitrarily pick between 2+ valid approaches (draw cards instead)
  • "Try again" on a system with no actual changes (redraw)

How It Works

  1. A Python script uses secrets to perform a Fisher-Yates shuffle
  2. 4 cards are drawn from the top of the shuffled deck
  3. Each card has an independent 50% chance of being reversed
  4. Claude reads the drawn cards' meaning files and interprets the spread
  5. The interpretation informs the planning direction

Card Organization

Each of the 78 Tarot cards has its own markdown file:

  • cards/major/ - 22 Major Arcana (The Fool through The World)
  • cards/wands/ - 14 Wands (Ace through King)
  • cards/cups/ - 14 Cups (Ace through King)
  • cards/swords/ - 14 Swords (Ace through King)
  • cards/pentacles/ - 14 Pentacles (Ace through King)