Serial Console on macOS with `cu`: The Simplest Built-In Alternative to `screen`

← Back to Blog

Why cu on macOS

If you need serial console access on macOS and you want the simplest possible tool that’s already on the system, cu is hard to beat.

On modern macOS, cu commonly comes from Taylor UUCP 1.07 (you can confirm with cu --help), and it’s designed to open a serial line with minimal configuration. That makes it ideal for “connect now” situations:

  • You’re offline or on a restricted network.
  • You’re on a clean Mac (no Homebrew, no extra installs).
  • You just need a reliable local terminal to a console port.

When you do have internet access and want a smoother workflow (multiple devices, organized sessions, shared access, and consistent logs), that’s where CliDeck fits naturally: CliDeck Workspace.


Quick Start (30 seconds)

  1. Plug in your USB-to-Serial adapter.
  2. Find the device name:
ls /dev/cu.*
  1. Connect (common console default is 9600 baud):
cu -l /dev/cu.usbserial-XXXX -s 9600
  1. Exit safely:
  • Press Enter (so the escape character is the first character on the line),
  • then type:
~.

Tip: The default escape character is ~. If you ever forget the available escape commands, the quickest way to discover them is usually ~? inside the session (or check man cu on your Mac).


Choosing the Right Port on macOS (/dev/cu.*)

On macOS you’ll typically see serial devices as:

  • /dev/cu.usbserial-* (often FTDI USB-serial)
  • /dev/cu.SLAB_USBtoUART (often Silicon Labs CP210x)
  • /dev/cu.wchusbserial* (often WCH CH340/CH9102)
  • /dev/cu.usbmodem* (often CDC/ACM-style devices)

The most reliable method: diff before/after

ls /dev/cu.* > /tmp/cu_before.txt
# plug in the adapter
ls /dev/cu.* > /tmp/cu_after.txt
diff /tmp/cu_before.txt /tmp/cu_after.txt

The new line(s) in the diff is your candidate port.


Setting Speed (Baud Rate)

In Taylor UUCP cu, speed is set with:

  • -s, --speed, or --baud
  • or the short form -# (where # is a number)

Examples:

cu -l /dev/cu.usbserial-XXXX -s 9600
cu -l /dev/cu.usbserial-XXXX -s 115200
cu -l /dev/cu.usbserial-XXXX -115200

Practical baud rate table (what to try first)

Use caseMost commonNext to try
Network gear console (typical)9600115200, 38400
Dev boards / UART debug11520057600, 9600
Older equipment960019200, 38400
Boot/debug on some platforms115200230400

If you see “garbage characters,” in most cases it’s simply the wrong baud rate. Switch between 9600 and 115200 first.


Parity, Line Settings, and Flow Control (What cu Actually Exposes)

Taylor UUCP cu exposes parity options directly:

  • Even parity: -e or --parity=even
  • Odd parity: -o or --parity=odd

Examples:

cu -l /dev/cu.usbserial-XXXX -s 9600 -e
cu -l /dev/cu.usbserial-XXXX -s 9600 --parity=odd

Software flow control (XON/XOFF)

By default, many setups handle XON/XOFF. If your device behaves strangely (paused output, missing characters) and you suspect software flow control is interfering, try disabling it:

cu -l /dev/cu.usbserial-XXXX -s 9600 --nostop

Carriage return mapping (CR → CRLF)

If the device expects CRLF or your terminal formatting looks off, you can map CR to CR/LF:

cu -l /dev/cu.usbserial-XXXX -s 9600 -t

The Options You’ll Actually Use (Taylor UUCP cu)

The most important flags on macOS (Taylor UUCP build) are:

OptionMeaningWhen to use
-l, --line <device>Use a named device (serial line)Your normal serial console case (/dev/cu.*)
-a, -p, --port <port>Use a named portUseful if you’ve defined ports in UUCP config
-s, --speed, --baud <n> or -<n>Set baud rateAlways
-e / -o / --parity=...Set parityWhen the device requires it
-E, --escape <char>Change escape character (default is ~)If ~ conflicts with your workflow
-h, --halfduplexEcho locallyRare, but useful for some links
--nostopDisable XON/XOFF handlingIf flow control breaks output
-t, --mapcrMap CR to CR/LFFor formatting quirks
-x, --debug <type> / -dDebug modeWhen troubleshooting

Important note: On this build, -h is half-duplex, not help. Use cu --help (double dash) to print help reliably.


How to Exit cu Cleanly

On macOS cu, the escape character is usually ~ (tilde). Escape sequences only work when ~ is the first character on the line, so:

  1. Press Enter
  2. Then type your escape command

Common patterns:

  • ~. — disconnect and exit
  • ~? — show escape help (if supported by your build)
  • Change escape char if needed:
cu -l /dev/cu.usbserial-XXXX -s 9600 -E %

Then you’d use % as the session escape prefix instead of ~.


Logging a cu Session (Practical Approach on macOS)

Taylor UUCP cu is intentionally minimal, and logging behavior can vary by build. The most reliable approach on macOS is to use the built-in script command to capture everything printed in your terminal:

script -q /tmp/serial-session.log
cu -l /dev/cu.usbserial-XXXX -s 9600
# exit cu with ~.
exit

This creates a readable log you can attach to tickets, paste into notes, or archive.

If you find yourself doing this often (multiple devices, repeatable workflows, centralized history), that’s a good point to switch to a toolchain that treats sessions and logs as first-class objects. That’s exactly one of the reasons CliDeck exists: CliDeck Features.


Troubleshooting (Based on Real macOS Output)

1) Permission denied and UUCP lock errors

You may see errors like:

  • cu: creat during lock (...) Permission denied
  • cu: p: Line in use

This happens because cu tries to create UUCP lock/spool files (commonly under /var/spool/uucp/) and your user may not have permission.

Fix A: Run cu with sudo (quickest test)

sudo cu -l /dev/cu.usbserial-XXXX -s 9600

If this works, you’ve confirmed a permissions/lock directory issue.

Fix B: Check the spool directory permissions

ls -ld /var/spool/uucp
ls -la /var/spool/uucp | head

If the directory doesn’t exist or is not writable by your user, cu won’t be able to create its lock/temp files without elevated privileges.

Fix C: Stale lock file (shows as “Line in use”)

If you’re sure nothing is using the port, a stale lock may be present. Inspect first:

ls -la /var/spool/uucp

If you see an obvious stale lock and you understand the risk, remove it with care (often requires sudo):

sudo rm -f /var/spool/uucp/LCK..*

Then retry cu. Be conservative here: deleting locks while another process truly uses the port can cause conflicts.


2) cu: must specify system, line, port or speed

This is normal when you run cu without enough arguments. For a serial console session you usually want at least:

  • -l /dev/cu.* (the device)
  • -s <baud> (speed)

Example:

cu -l /dev/cu.usbserial-XXXX -s 9600

3) Nothing prints (blank screen)

Most common causes:

  • Wrong port (/dev/cu.* mismatch)
  • Wrong baud rate (try 9600 then 115200)
  • Wiring issue (RX/TX swapped, incorrect adapter, wrong ground)
  • The device only speaks after boot or after you press Enter

Checklist:

ls /dev/cu.*
cu -l /dev/cu.usbserial-XXXX -s 9600
# press Enter a few times
# try again with 115200

4) Garbled output (“random symbols”)

Almost always baud mismatch. Try:

  • 9600 (most network console defaults)
  • 115200 (many dev/UART consoles)

Also check whether you need parity or whether XON/XOFF is interfering:

cu -l /dev/cu.usbserial-XXXX -s 9600 --nostop
cu -l /dev/cu.usbserial-XXXX -s 9600 -e

Mini FAQ

Is cu the best option on macOS?

If you need a built-in, offline, no-install serial console tool, cu is often the best choice. It’s simple, fast, and available when you have nothing else.

When should I use CliDeck instead?

If you want:

  • multiple devices and sessions organized in one workspace,
  • consistent logging and session history,
  • browser access and team workflows,

then cu becomes a fallback tool rather than your primary workflow. That’s where CliDeck fits: CliDeck Workspace.


Bottom Line

Use cu when you need the quickest, most reliable offline way to connect to a serial console on macOS.

And when you’re ready to move beyond “connect and exit” into a workflow with structured sessions, consistent logs, and a browser-first experience, take a look at CliDeck: CliDeck Workspace.