I realized that awk is ideal for expect-like automation. The difficulty I faced was how can awk "control" another program's (in this case, an irc client) both stdin and stdout, i.e., awk would need to both read from the program's stdout and write to its stdin. I solved this program by creating a FIFO for taking inputs, and hook the program to it. Below is the detail:

First, let's set up our system:

Now this bot is up and running without human intervention. In case you want to interact with this IRC session, you could access the intput using cat:

The system looks like this:

+---------------------------+
|                           |
|           cat             |
|                           |
+------------+--------------+
|
|
v
+--+--+
| ups +<---------------+
+--+--+                |
|                   |
|                   |
v                   |
+------------+--------------+    |
|                           |    |
| nc chat.freenode.org 6667 |    |
|                           |    |
+------------+--------------+    |
|                   |
|                   |
v                   |
+------------+--------------+    |
|                           |    |
|           awk             +----+
|                           |
+---------------------------+


One can connect to Freenode IRC using SSL instead, either one of below works:

openssl s_client -quiet -connect chat.freenode.org:6697
socat stdio openssl-connect:chat.freenode.org:6697


# Taking it further

A pattern can be observed here - the main program is the IRC session, where its outputs are streaming through a pipeline unmodified. A set of bot programs takes IRC output as stdin, and their outputs are the bot command that should be sent back to the IRC. Then, we can use a utility tee program (proctee) to chain those bots together.