How experienced are you?
Hard: Write a bounded-A* pathing engine. (Currently BTS uses an unbounded A* pather, which ... sucks in a number of cases)
Medium: Write a stack-on-stack combat simulator that returns a description of what is left after the fight, and can be called repeatedly with new stacks thrown in, that doesn't change the actual game state.
Easy: Write a single-unit vs single-unit combat simulator that returns that status of each unit in such a way that it can be called again on one of the units.
Ideally do the above with minimal changes to the existing code base, as little copy/paste as possible, etc etc.
Having the above gives us the ability to run an assault simulation so the AI doesn't fruitlessly attack a heavily fortified enemy city, and instead might wait a turn for the catapults to come online to soften it up. In other cases, the AI might blitz because it is likely to win under the blitz.
And they are quite isolated.
If you want to look into a less code/algorithm heavy problem, the issue of "catapults not attacking invading stacks" might be interesting. I think that is still an outstanding problem with the AI.