Ask when it helps
For substantial, ambiguous work, Joy asks what should remain yours. Clear or trivial tasks keep moving.
An Agent Skill for thoughtful delegation
Joy helps you decide what to delegate without giving away the parts of programming you value. It asks a focused question before an AI agent takes over.
AI can remove friction.
Joy keeps it from removing your part before you choose.
A movable boundary
Meaningful challenge and incidental toil are not the same thing. Joy lets you keep the design, discovery, or craft you want—and hand off the rest without guilt.
For substantial, ambiguous work, Joy asks what should remain yours. Clear or trivial tasks keep moving.
Learning, craftsmanship, exploration, and fast delivery are equally valid goals. Delegating everything is valid too.
Your latest instruction wins. Move work between Keep, Pair, and Delegate without ceremony or pressure.
Choose the session you need
Be explicit, or let Joy infer the lightest useful boundary from your request.
pairdefaultFocused, understandable increments with consequential choices discussed before implementation.
learnQuestions, explanations, and graduated hints while the central solution stays yours.
craftYou own architecture and interesting implementation; the agent handles support work.
shipSafe autonomous execution, a small complete change, validation, and a concise handoff.
tidyEvidence-based Keep, Refine, and Let go recommendations before destructive cleanup.
offReturn to normal assistant behavior without carrying a previous Joy boundary forward.
See the boundary move
Watch real CLI sessions. Pause, seek, change the pace, or select terminal text while Joy protects a different kind of ownership.
An end-to-end case study
Follow a real Claude Code review of an executable webhook worker. The delivery semantics remain developer-owned while Joy pairs on the failure invariant and delegates verification.
claim = self._repository.claim_due(now=now, lease_seconds=self._policy.lease_seconds)
+ self._transport.send(
+ claim.endpoint,
+ claim.payload,
+ idempotency_key=claim.idempotency_key,
+ )
+ if crash_after_send:
+ raise CrashAfterSend("delivery succeeded before its local acknowledgement")
+ if not self._repository.mark_delivered(claim, now=now):
+ raise LostLease(claim.delivery_id)
Why it matters: the remote effect and local acknowledgement cannot be atomic. The chosen contract permits redelivery with the same idempotency key rather than pretending exactly-once delivery exists.
Crash after sendRedelivers after lease expiry with the same key.
Transport failureWaits for exponential backoff before retrying.
Stale acknowledgementCannot overwrite a newer claim generation.
test_crash_after_send_redelivers_with_one_receiver_effect ... ok
test_stale_worker_cannot_acknowledge_a_newer_claim ... ok
test_transport_failure_waits_for_backoff_before_retry ... ok
Ran 3 tests
OK
A successful remote effect may be repeated after a crash. The stable key is part of the contract.
A stale worker cannot acknowledge or reschedule work after a newer lease has been claimed.
The example has no dead-letter policy. That omission remains an explicit product decision, not a hidden default.
SQLite persistence, a deduplicating fake receiver, fault injection, and the test harness support the chosen semantics.
A small skill, no runtime
The canonical skill is plain Markdown, follows the Agent Skills standard, and has no runtime dependencies.
npx skills add JGalego/Joy --skill joy --agent claude-code --global --yes
The choice stays yours