diff --git a/include/action.h b/include/action.h
index 0e60abc5150011598dff8cdd17a1bd7bb3007293..480b6c47682ec0638124904925f9dc457ba9bae4 100644
--- a/include/action.h
+++ b/include/action.h
@@ -119,6 +119,11 @@ public:
         return true;
     }
   }
+
+  friend std::ostream& operator<<(std::ostream& os, const Action& action);
+
 };
 
+std::ostream& operator<<(std::ostream& os, const Action& action);
+
 #endif  // CCF_IMMERSIVE_SORTING_ACTION_H_
diff --git a/src/action.cpp b/src/action.cpp
index 1eba944a6af742209c2a402367a6a80451cddb04..f8b15695efe5eca3d59fe6293941cd4aaf4e1546 100644
--- a/src/action.cpp
+++ b/src/action.cpp
@@ -1 +1,13 @@
 #include "action.h"
+
+std::ostream& operator<<(std::ostream& os, const Action& action)
+{
+  switch (action.type_) {
+    case Action::PICK_DROP:
+      os << "[pick " << action.source_ << " and drop it into " << action.target_ << "]";
+      break;
+    default:
+      os << "[unknown action with source " << action.source_ << " and target " << action.target_ << "]";
+  }
+  return os;
+}
\ No newline at end of file