| name | clj-repl |
| description | Start or connect to a Clojure/ClojureScript/Babashka nREPL. Detects project type and starts appropriate REPL in background. Use when user wants to evaluate code, start REPL, or needs nREPL connection. |
Clojure REPL Skill
Start or connect to an nREPL server for REPL-driven development.
Quick Reference
| Command | Action |
|---|
/clj-repl | Auto-detect project, start REPL (asks if existing found) |
/clj-repl fresh | Restart all - stop existing, start new (no prompts) |
/clj-repl keep | Use existing REPLs if running (no prompts) |
/clj-repl bb | Start Babashka nREPL |
/clj-repl clj | Start JVM Clojure nREPL |
/clj-repl shadow | Start shadow-cljs nREPL |
/clj-repl status | Check tracked + discovered REPLs |
/clj-repl stop | Stop all tracked REPLs |
/clj-repl --verbose | Show detailed MCP tool output |
Output Style
Default: Concise - Show brief status updates, final summary table only.
With --verbose - Show MCP tool call details and intermediate output.
Example concise output:
Starting backend + shadow-cljs...
✓ Backend REPL on port 1669
✓ shadow-cljs on port 9630
✓ App server started
| Service | Port | URL |
|---------|------|-----|
| Backend | 1669 | - |
| shadow-cljs | 9630 | http://localhost:9630 |
| Web App | 8080 | http://localhost:8080 |
DO NOT show raw MCP JSON responses or tool call internals unless --verbose is specified.
CRITICAL: Use MCP Tools for REPL Operations
After REPLs are running, ALWAYS use forj MCP tools instead of bash commands:
| Task | MCP Tool | NOT bash |
|---|
| Evaluate code | repl_eval | clj-nrepl-eval -p ... |
| Find REPLs | discover_repls | clj-nrepl-eval --discover-ports |
| Reload namespace | reload_namespace | manual require |
| Look up docs | doc_symbol | (doc ...) |
| Eval at line | eval_at | copy/paste |
| Run tests | run_tests | clj -M:test |
Bash is ONLY for starting/stopping REPL servers. All evaluation should use MCP tools.
You Are NOT Done Until...
Before reporting success, ALL of these must be true:
⚠️ COMMON MISS: The :dev-http port in shadow-cljs.edn!
grep ":dev-http" shadow-cljs.edn
Instructions
Step 1: Check for Existing Processes
Handle flags first:
| Flag | Behavior |
|---|
fresh | Skip prompts. Stop all tracked processes, start new ones. |
keep | Skip prompts. Use existing REPLs if found, start only what's missing. |
| (none) | Ask user if existing processes found. |
Check for tracked processes:
list_tracked_processes
discover_repls
With fresh flag:
stop_project # Stop all tracked processes
# Then proceed to start new ones (Step 2+)
With keep flag:
- If REPLs are already running for this project → report them and done
- If some are missing → start only what's missing
- No prompts, just proceed
With no flag (default):
If there are tracked processes that are still alive:
- Tell the user what's already running (brief: "Found backend on 1669, shadow on 9630")
- Ask: "Keep existing, restart fresh, or stop only?"
If processes are tracked but all dead, clean them up silently:
stop_project
Step 2: Detect Project Type & What to Start
Check which config files exist:
| Files Present | What to Start |
|---|
deps.edn + shadow-cljs.edn + app.json | Backend + shadow-cljs (check for multiple builds!) + Expo |
deps.edn + shadow-cljs.edn | Backend + shadow-cljs (check for multiple builds!) |
shadow-cljs.edn + app.json | shadow-cljs + Expo |
deps.edn only | Backend REPL |
shadow-cljs.edn only | shadow-cljs |
bb.edn only | Babashka REPL |
⚠️ CHECK FOR MULTIPLE SHADOW BUILDS:
Many projects have BOTH :web and :mobile builds. Check shadow-cljs.edn:
grep -E "^\s+:(web|mobile|app|main)" shadow-cljs.edn
If you see multiple builds (e.g., :web AND :mobile):
- Start both shadow builds:
bb shadow:web AND bb shadow:mobile
- Don't assume one is enough!
Example project with both:
bb dev # Backend REPL
bb shadow:web # Web frontend (port 8080)
bb shadow:mobile # Mobile frontend
bb expo:web # Expo dev server
Do NOT stop after starting REPLs. The app server must also be running.
Step 3: Use bb Tasks (Required When Available)
If bb.edn has relevant tasks, you MUST use them instead of raw commands.
| Task | Use For |
|---|
bb dev or bb repl | Backend REPL |
bb shadow:mobile | ClojureScript for Expo (outputs to app/) |
bb shadow:web | ClojureScript for browser |
bb expo / bb expo:android / bb expo:ios / bb expo:web | Expo dev server |
Only fall back to raw commands if NO bb task exists.
Step 4: Start ALL Required Processes
Use run_in_background: true for each. Start them all before moving on.
First, create log directory:
mkdir -p .forj/logs
Use setsid -f with tee to daemonize processes (survive terminal close):
setsid -f bash -c 'bb dev 2>&1 | tee .forj/logs/backend.log' &
setsid -f bash -c 'bb shadow:web 2>&1 | tee .forj/logs/shadow.log' &
IMPORTANT: Track each process after starting!
After each background process starts, call track_process with the PID (from Bash tool output):
track_process with pid=<PID> name="backend-repl" port=<PORT> command="bb dev"
track_process with pid=<PID> name="shadow-cljs" port=9630 command="bb shadow:mobile" # or shadow:web
track_process with pid=<PID> name="expo" port=8081 command="bb expo"
This enables /clj-repl stop to cleanly shut down all processes later.
To view logs later, use the view_repl_logs MCP tool:
view_repl_logs with log: "all" - see all logs at once
view_repl_logs with log: "backend" / "shadow" / "expo" - specific log
lines: 50 (default) - number of lines to return
Full-stack with web + mobile (check shadow-cljs.edn for builds!):
mkdir -p .forj/logs
setsid -f bash -c 'bb dev 2>&1 | tee .forj/logs/backend.log' &
setsid -f bash -c 'bb shadow:web 2>&1 | tee .forj/logs/shadow-web.log' &
setsid -f bash -c 'bb shadow:mobile 2>&1 | tee .forj/logs/shadow-mobile.log' &
Step 4a: Mobile Device Selection (For Mobile Projects)
First, check if Expo Web is available:
grep -q "react-native-web" package.json && echo "WEB_ENABLED"
Ask the user (include Web option only if detected):
"How do you want to run the app?"
- Android emulator (launches automatically)
- iOS simulator (launches automatically)
- Physical device (enter URL in Expo Go)
- Web browser (if react-native-web installed) - great for Playwright/automation testing
Use bb tasks (NOT npx):
Android:
setsid -f bash -c 'bb expo:android 2>&1 | tee .forj/logs/expo.log' &
iOS:
setsid -f bash -c 'bb expo:ios 2>&1 | tee .forj/logs/expo.log' &
Physical Device (Manual URL):
LOCAL_IP=$(ip route get 1 | awk '{print $7; exit}')
setsid -f bash -c 'bb expo 2>&1 | tee .forj/logs/expo.log' &
sleep 3
echo "Open Expo Go on your device and enter URL:"
echo " exp://${LOCAL_IP}:8081"
Web Browser (if react-native-web installed):
setsid -f bash -c 'bb expo:web 2>&1 | tee .forj/logs/expo.log' &
sleep 3
echo "Open http://localhost:8081 in your browser"
Full-stack web:
mkdir -p .forj/logs
setsid -f bash -c 'bb dev 2>&1 | tee .forj/logs/backend.log' &
setsid -f bash -c 'bb shadow:web 2>&1 | tee .forj/logs/shadow.log' &
Backend only:
mkdir -p .forj/logs
setsid -f bash -c 'bb dev 2>&1 | tee .forj/logs/backend.log' &
Step 5: Start Application Server (REQUIRED - Don't Skip!)
REPL running ≠ Done. The application server must be started from within the REPL.
Detection priority:
-
Common functions - Search src/**/core.clj for:
(defn start-server → eval (<namespace>/start-server)
(defn start → eval (<namespace>/start)
(defn go → eval (<namespace>/go)
-
State management - Check requires:
mount.core → eval (mount.core/start)
integrant.core → look for (ig/init ...)
component → look for (component/start ...)
-
Comment blocks - Read them for startup examples
-
Fallback - Read core.clj and figure out how to start it
Example:
repl_eval with code="(require '[myapp.core :as core] :reload)"
repl_eval with code="(core/start-server {:port 3000})"
Step 6: Verify Everything Works
Wait 2-5 seconds after starting, then:
discover_repls
Test each REPL:
repl_eval with code="(+ 1 2)" port=<backend-port>
repl_eval with code="(+ 1 2)" port=<shadow-port>
Step 7: Report Success (Only After Everything Running)
Final checklist before reporting:
Check shadow-cljs.edn for dev-http ports:
grep -o ':dev-http {[0-9]*' shadow-cljs.edn
If :dev-http is present (e.g., {8080 "resources/public"}), the web app is served on that port.
Report all services in a table:
Include only the services actually running for this project type.
Tell the user:
- All processes started
- Port numbers for each service
- URLs for accessing each service
- They can now use forj MCP tools
Evaluating Code
When user asks to evaluate code, ALWAYS use repl_eval MCP tool:
repl_eval with code="(+ 1 2 3)"
The tool auto-discovers ports. Do NOT shell out to clj-nrepl-eval.
Checking Status (/clj-repl status)
Run both tools and summarize:
list_tracked_processes
discover_repls
Report to user:
- Tracked processes: What this session started (with alive/dead status)
- Discovered REPLs: All nREPL servers found (may include untracked ones)
Stopping REPLs
Use the stop_project MCP tool to stop all tracked processes:
stop_project
This kills all REPLs, shadow-cljs, and Expo processes that were tracked with track_process.
To check what's tracked before stopping:
list_tracked_processes
Manual fallback (if processes weren't tracked):
lsof -i :<port>
kill $(lsof -t -i :<port>)
Monorepo Handling
For projects with multiple build files:
- Use
discover_repls to see what's running
- Ask user which to start if needed
- Multiple REPLs can run on different ports
- MCP tools auto-discover all ports
Troubleshooting
No REPLs found:
- Use
discover_repls to check what's running
- Try starting one with
/clj-repl bb or /clj-repl clj
Wrong project context:
The nREPL's working directory determines the project. Make sure to start the REPL from the correct directory.
Port conflicts:
Each REPL needs a unique port. Use different ports for multiple REPLs.
Notes
- Babashka nREPL is fast to start - good for quick scripts
- JVM Clojure takes 5-10 seconds to start but has full Clojure
- Shadow-cljs provides ClojureScript REPL with hot reload
- All REPL interaction should use MCP tools, not bash