This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
intemporal is a Clojure/ClojureScript library inspired by Temporal.io and Uber Cadence. It enables defining functions with side effects that can persist and resume their state, providing resilience to process crashes.
- Activities: Protocol implementations or functions that handle side effects. Activities are the unit of work that can fail and be retried.
- Workflows: Functions that orchestrate activities with at-least-once semantics. Workflows can safely resume after crashes by replaying from persisted event history.
- Event Sourcing: Workflow state is reconstructed from an event log stored via the
IStoreprotocol. - Replay: On resume, workflows replay their event history to reconstruct state without re-executing activities.
The codebase is organized into several layers:
-
Core API (src/intemporal/core.cljc)
stub- Creates activity stubs for use in workflowsstub-protocol- Creates protocol stubs for use in workflowsstart-workflow,resume-workflow- Workflow execution entry pointsmake-workflow-engine,with-workflow-engine- Engine lifecyclewait-for-signal,send-signal,sleep,async,join- Workflow operationsrun-child-workflow,cancel-workflow- Child workflows and cancellation
-
Protocol Definitions (src/intemporal/protocol.cljc)
IStore- Workflow persistence (history, signals, cancellation)IActivityExecutor- Activity execution with timeout/retryIScheduler- Timer schedulingIWorkflowObserver- Event observation for monitoring/tracing
-
Internal Components (src/intemporal/internal/)
context.cljc- Dynamic workflow context with sequence counters, pending eventsexecution.clj/execution.cljs- Workflow execution engine (platform-specific)runtime.clj/runtime.cljs- Default implementations ofIActivityExecutorandIScheduler(platform-specific)activity.cljc- Activity registration and metadataerror.cljc- Error types (suspensions, interruptions, rejections, cancellations)logging.cljc- Structured logging via taoensso/telemeremacros.cljc-stub-protocolmacrofns/start_workflow.clj/fns/start_workflow.cljs- Workflow start logic (platform-specific)
-
Store Implementations (src/intemporal/store.cljc)
InMemoryStore- In-memory implementation ofIStore- Additional stores: FoundationDB (
store/fdb.clj,:fdbalias), JDBC (store/jdbc.clj,:jdbcalias)
-
Observer (src/intemporal/observer.cljc)
noop-observer,make-logging-observer- Observer factoriesobserver/otel.clj- OpenTelemetry observer implementation
- Sequence Numbers: Each activity/operation gets a monotonic sequence number for deterministic replay
- Suspensions: Workflows can suspend (e.g., waiting for signal, timer) and resume later
- Cancellation: Workflows check cancellation status at each sequence point
- Pending Events: During workflow execution, events are buffered and atomically saved to store
Ensure you run grep with --color=never
grep --color=never
# Run all tests (includes JVM and ClojureScript tests)
bin/kaocha
# Run specific test suite
bin/kaocha :test # JVM tests only
bin/kaocha :in-memory # In-memory tests (skips :integration)
bin/kaocha :test-cljs # ClojureScript tests
# Run a single test namespace (note: use hyphens, not underscores)
bin/kaocha :test --focus intemporal.tests.signal-test
# Run crash recovery tests
bin/kaocha :test --focus intemporal.tests.crash.signal-wait-crash-test
bin/kaocha :test --focus intemporal.tests.crash.future-cancel-test
# Run tests via npx
npx shadow-cljs compile node
# Focus cljs tests
bin/kaocha :test-cljs --focus cljs:intemporal.tests.crash.future-cancel-test
Important: Test namespaces use hyphens (e.g., signal-wait-crash-test), which map to underscored file names (signal_wait_crash_test.clj).
Test configuration is in tests.edn:
- Line 37:
:kaocha.filter/skip-meta [:crash]can be uncommented to skip crash tests - Coverage reports:
target/coverage/index.html - JUnit XML reports:
target/test-reports/report.xml
# Start REPL with development dependencies
clojure -A:dev
# With FoundationDB support
clojure -A:dev:fdb
# With JDBC/PostgreSQL support
clojure -A:dev:jdbc# Compile main namespaces
clojure -T:build compile-main
# Compile development namespaces
clojure -T:build compile-dev
# Build JAR
clojure -T:build jarThe test runner (bin/kaocha) has a commented-out debug agent on port 5005 that can be enabled:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
The project includes OpenTelemetry instrumentation (see deps.edn :dev alias, _jvm-opts):
- Java agent:
./opentelemetry-javaagent.jar - OTLP endpoint:
http://localhost:4317(gRPC) - Service name:
intemporal - Metrics and logs are disabled by default
- Note: The OTel JVM opts use the
_jvm-optskey (underscore prefix), so they are not active by default - they must be manually enabled
Workflows are regular functions that use stub to wrap activity calls:
(require '[intemporal.core :as intemporal])
(defn my-activity [arg]
[:processed arg])
(defn my-workflow [arg]
(let [act (intemporal/stub #'my-activity)]
(act arg)))Activities can be:
- Regular functions (via var):
(intemporal/stub #'my-function) - Protocol methods:
(intemporal/stub-protocol MyProtocol)
(require '[intemporal.core :as intemporal])
;; Using with-workflow-engine (ensures cleanup)
(intemporal/with-workflow-engine [engine {:threads 4}]
(intemporal/start-workflow engine my-workflow [arg]))
;; Or manually managing the engine
(let [engine (intemporal/make-workflow-engine :threads 4)]
(try
(intemporal/start-workflow engine my-workflow [arg])
(finally
(intemporal/shutdown-engine engine))))- test/intemporal/tests/ - Main test directory
async_test.clj/.cljs- Async operation testscancellation_test.clj/.cljs- Workflow cancellationchild_workflow_test.clj/.cljs- Nested workflow testserror_test.clj/.cljs- Error handling and retry policiessignal_test.clj/.cljs- Signal send/receivetimer_test.clj/.cljs- Timer schedulingtracing_test.clj- OpenTelemetry tracing (JVM only)protocol_test.clj- Protocol testsreplay_check_test.clj- Replay verificationstub_protocol_test.cljc- Protocol stubbing testscontext_macros_test.cljs- Context macros (ClojureScript only)utils.cljc- Test utilities- store/ - Store-specific tests
- crash/ - Crash recovery scenarios
Tests in test/intemporal/tests/crash/ verify workflow resilience:
- Execute workflow until suspension point
- Simulate crash (exception)
- Resume workflow and verify activities aren't re-executed
- Check workflow completes with correct result
- Clojure 1.12.1+
- taoensso/telemere (structured logging)
- clj-otel-api (OpenTelemetry tracing)
- macrovich (cross-platform macros)
- promesa (promises, required for ClojureScript)
- cheshire (JSON)
- shadow-cljs
:fdb- FoundationDB client:jdbc- PostgreSQL/JDBC persistence (next.jdbc, PostgreSQL, HikariCP, migratus):cljs- ClojureScript support:dev- Testing libraries (Kaocha, kaocha-cloverage, kaocha-junit-xml, kaocha-cljs, logback, spy, matcher-combinators, clj-async-profiler)
- Determinism: Workflows must be deterministic for replay to work correctly. Use activities for any non-deterministic operations (random numbers, time, I/O).
- Namespace Conventions: File names use underscores (
signal_test.clj), namespace names use hyphens (signal-test). - Production Readiness: Per README, this library is NOT production-ready. Use at your own risk.