I see two options that have their pros and cons. What are your thoughts on this?
Neither. You should have one command buffer per-task, per-thread.
The whole point of the command buffer paradigm is to be able to thread your rendering operation. To generate rendering commands on multiple threads at the same time. If you want to take maximum advantage of this, then you need to have at least one command buffer per-thread.
But at the same time, threading a renderer can be somewhat difficult. Consider shadow mapping. You need to walk your object hierarchy to find out which objects are “visible” from the light. But you also need to do that to determine which objects are visible for the main rendering. And the two lists of objects won’t be the same, even though they’re starting from the same source set of objects. And the commands you need for shadow map rendering are not the commands you need for regular rendering.
For best efficiency (probably), you will want to only walk the object hierarchy once. So on the thread(s) that do this, they should be generating two command buffers. One for the shadow map rendering and one for the main rendering. For each object, they issue commands for both CBs, as needed.
You would eventually send those CBs to the queue submissions thread, which will know about them and do something useful with them.
Vulkan works best when your rendering system has a well-defined structure to it. That is, you build “boxes” that you can pour content into. You have a “box” for objects that cast shadows, a “box” for regular objects, a “box” for particles, a “box” for post-processing effects, and so on. This way, you can tailor your threading and CB-building system for the needs of your renderer.
However, if you’re just starting out, that’s all extremely complicated. I would instead focus on just using a single command buffer. It’ll be easier to go from that to multiple, threaded CBs than it will if you start from having one CB per object.