Determine if braces in a string are balanced in Clojure
Recursion

Use recur to do tail-call recursion:


  Note that recur is the only non-stack-consuming looping construct in
  Clojure. There is no tail-call optimization and the use of self-calls
  for looping of unknown bounds is discouraged. recur is functional and
  its use in tail-position is verified by the compiler.


Destructuring

You can use :as to avoid the unnecessary let here:

  ([string stack]
    (let [[first-char &amp; other] string]


Instead:

 ([[first-char &amp; other :as string] stack]


Repeated Constants

Here you are entering the same data by hand twice:

(def braces #{\( \) \[ \] \{ \}})

(def pairs { \) \(,
             \] \[,
             \} \{ })


Instead you can do:

(def braces (set (concat (keys pairs) (vals pairs))))


Testing

Use clojure.test to do unit testing. It does have a standard and useful failure reporting. You needn't write a test harness like test-strings yourself. You should only report failures, because test are only useful when they are reporting failures. Most your test should be passing at any time, so any relevant information (a failing test case) should not be lost in noise (dozens of lines of "test-case-xyz passed just as the 937 time before").

Make a habit of putting test code in a separate namespace that does depend on the code tested, but not vice-versa.

After requiring clojure.test:

... (:require [clojure.test :refer :all] ...


You define tests like this:

(deftest non-braces-ignored
  (is (is-balanced? "Hello { ( world ) } [] end")))

(deftest empty-string-is-brace-balanced
  (is (is-balanced? "")))

(deftest some-long-balanced-string
  (is (is-balanced? "{[] () {[{{ }}]} ([{}])}")))


You can group several of similar tests like this until you can find a descriptive name for them, although failure message is not as useful as above tests:

(deftest examples-of-non-balanced-strings
  (are [x] (not (is-balanced? x))
       "Hello { world"
       "{{"
       "])"
       "}}{{"
       "{[))"))


and run these tests like this:

(run-tests)


Namespaces

Don't put function calls inside a namespace. Reloading a namespace should be idempotent.
Also if the function call is something like (main) you don't gain much; 
however if you are calling some non-trivial initialization code then it deserves it own function.