If you want to mirror how e.g. `Times` works, then what you want to do is exploit the `OneIdentity` attribute (which `NonCommutativeMultiply` already has), `Default` values and `Optional` patterns, and an identity value for `NonCommutativeMultiply`.

If `f` has the attribute `OneIdentity`, that means that `f[x]`, `f[f[x]]`, etc. will match `x`.

`Optional` patterns match a pattern to a provided default value if the expression does not appear. But there are two ways to provide a default value: either inline or via a value that's globally associated with the enclosing head. For example, if we have `f[a_:0, b_] := {a,b}`, then `f[2]` will be `{0,2}` thanks to the inline `Optional` pattern `a_:0`. But we could also use `f[a_., b_]` (`a_.` is `Optional[a]`) together with a separate evaluation of `Default[f] = 0` to get the same result.

This works for pattern matching too: e.g. `Default[Times]` is `1`, and `f[Times[x_.,3]] := x` means that `f[3 y]` gives `y`, while `f[3]` gives `1`. The `OneIdentity` attribute means that `3` matches `Times[3]` which matches `Times[x_.,3]`.

To be honest, I'm not 100% sure why `b+c` doesn't then match `NonCommutativeMultiply[a___,b_+c_,d___]`. It seems `OneIdentity` only meshes well with `Optional` patterns. However, it *does* match `NonCommutativeMultiply[a_., b + c, d_.]`.

Here's a gotcha to watch out for: the `Default` value must be set *before* any definitions involving default patterns are evaluated. I suspect `Optional` is partially magical.

### Making `NonCommutativeMultiply` behave well

We then also need to actually make our `Default` value actually behave like an identity for `NonCommutativeMultiply`. To do this, we add a definition using the intercept trick.

We *also* need to make `NonCommutativeMultiply[a]` be `a` and `NonCommutativeMultiply[]` be the default value. Due to, I suspect (but possibly not), the magic of `Optional`, we need to temporarily clear `NonCommutativeMultiply`'s attributes while setting that definition.

So, putting it all together:
```
Unprotect[NonCommutativeMultiply];

Default[NonCommutativeMultiply] = 1; (* or whatever value you'd like here *)

Block[{a = Attributes[NonCommutativeMultiply]},
  Attributes[NonCommutativeMultiply] = {};
  NonCommutativeMultiply[a_.] := a;
  Attributes[NonCommutativeMultiply] = a;
  ];

NCMIntercept = True;

NonCommutativeMultiply[a_, b__] :=
 Block[{NCMIntercept = False},
  NonCommutativeMultiply @@ DeleteCases[{a,b}, Default[NonCommutativeMultiply]]
 ] /; NCMIntercept

Protect[NonCommutativeMultiply, NCMIntercept];

NCExpand[a_. ** (b_ + c_) ** d_.] := a ** b ** d + a ** c ** d
```
(Note that while `NCExpand[b + c]` works as expected, `NCExpand[b]` is still undefined! Another definition (`NCExpand[a_] := a`) is needed.)

It is possible to do this a bit differently if you want `NonCommutativeMultiply[a]` to not evaluate further (the default behavior), perhaps by using `Default[NonCommutativeMultiply] := Sequence[]`. I haven't explored this though.

Hope this helps! :)