diff --git a/htools/Ganeti/HTools/Program/Hbal.hs b/htools/Ganeti/HTools/Program/Hbal.hs
index c7e63728edf7b406a72a9fd24bec1ba4dae5794b..deea30f522c4c6dfeb00b34c154c95034a7e23ac 100644
--- a/htools/Ganeti/HTools/Program/Hbal.hs
+++ b/htools/Ganeti/HTools/Program/Hbal.hs
@@ -56,11 +56,13 @@ import Ganeti.HTools.CLI
 import Ganeti.HTools.ExtLoader
 import Ganeti.HTools.Types
 import Ganeti.HTools.Loader
+import Ganeti.OpCodes (wrapOpCode, setOpComment, OpCode, MetaOpCode)
 import Ganeti.Types (fromJobId)
 import Ganeti.Utils
 
 import qualified Ganeti.Luxi as L
 import Ganeti.Jobs
+import Ganeti.Version (version)
 
 -- | Options list and functions.
 options :: IO [OptType]
@@ -99,6 +101,12 @@ options = do
 arguments :: [ArgCompletion]
 arguments = []
 
+-- | Wraps an 'OpCode' in a 'MetaOpCode' while also adding a comment
+-- about what generated the opcode.
+annotateOpCode :: OpCode -> MetaOpCode
+annotateOpCode =
+  setOpComment ("rebalancing via hbal " ++ version) . wrapOpCode
+
 {- | Start computing the solution at the given depth and recurse until
 we find a valid solution or we exceed the maximum depth.
 
@@ -205,6 +213,7 @@ execJobSet _      _  _  _    [] = return True
 execJobSet master nl il cref (js:jss) = do
   -- map from jobset (htools list of positions) to [[opcodes]]
   let jobs = map (\(_, idx, move, _) ->
+                      map annotateOpCode $
                       Cluster.iMoveToJob nl il idx move) js
   let descr = map (\(_, idx, _, _) -> Container.nameOf il idx) js
   putStrLn $ "Executing jobset for instances " ++ commaJoin descr
diff --git a/htools/Ganeti/Luxi.hs b/htools/Ganeti/Luxi.hs
index b7d99b9445c4dadec377ae1a7901bc4154d2e407..a59bd9bb21522dc656748023f200c722af71ea2a 100644
--- a/htools/Ganeti/Luxi.hs
+++ b/htools/Ganeti/Luxi.hs
@@ -138,10 +138,10 @@ $(genLuxiOp "LuxiOp"
   , (luxiReqQueryTags,
      [ pTagsObject ])
   , (luxiReqSubmitJob,
-     [ simpleField "job" [t| [OpCode] |] ]
+     [ simpleField "job" [t| [MetaOpCode] |] ]
     )
   , (luxiReqSubmitManyJobs,
-     [ simpleField "ops" [t| [[OpCode]] |] ]
+     [ simpleField "ops" [t| [[MetaOpCode]] |] ]
     )
   , (luxiReqWaitForJobChange,
      [ simpleField "job"      [t| JobId   |]
@@ -443,7 +443,7 @@ parseSubmitJobResult v =
       show (pp_value v)
 
 -- | Specialized submitManyJobs call.
-submitManyJobs :: Client -> [[OpCode]] -> IO (ErrorResult [JobId])
+submitManyJobs :: Client -> [[MetaOpCode]] -> IO (ErrorResult [JobId])
 submitManyJobs s jobs = do
   rval <- callMethod (SubmitManyJobs jobs) s
   -- map each result (status, payload) pair into a nice Result ADT