As a software developer, and someone who knows a bit about intellectual property issues, I'd like to suggest an even broader idea.
If you're looking for a pet project, why not a deckbuilder-builder?
In other words, write a deckbuilder game framework in which all systems are abstracted, configurable and scriptable. In fact, you might even study some other deckbuilders to see if there are mechanisms that Dominion doesn't have that your project could implement.
The reason I suggest this is partly because even including the base cards, or using terminology or card names particular to Dominion, would be copyright violation, even for a project that you intend to release for free for fun. But partly because what I'm proposing would be more generally interesting.
If what you release is a configurable system, containing no card names or mechanisms, then individual users of your system could create their own configurations, card names, designs, artwork, whatever. If those people chose to use Dominion images, names, mechanisms, then if they already owned Dominion, it would fall under fair use. If they did not, or if they shared these configuration files with other users who did not own Dominion, then that would be a copyright violation, but it would no longer be your responsibility.
Maybe this sounds like a grey area, like a file sharing framework that's technically not responsible if their users use it primarily for piracy, but I think you could end up with something much different here, especially if your system were powerful enough to mimic many different existing deckbuilders, or even give users the creative potential to make new ones and experiment with game design mechanisms.
The fascinating thing about approaching a project this way is to start thinking about how abstract you need to be in order to create a configurable system. Instead of thinking about actions, buys, coin, debt, just think about imaginary values A, B, C, D, etc. that can be named anything and can be added to or subtracted from. (Wait a minute... Actions, Buys, Coin, Debt? That was completely accidental, I swear.) Empty your mind of specifics and see how far you can generalize.
Likewise, where can cards exist? Don't think in terms of supply piles, deck, hand, discard, in play, tavern mat, etc. Cards can go into card containers. Card containers have or do not have a number of attributes: Shared or player-specific, ordered or unordered, public/player/hidden/head-only/tail-only visibility, etc. The act of "drawing" is taking a card from the head of container A (player-specific, ordered, hidden) and adding it container B (player-specific, unordered, player visible). "gaining" is taking a card from the head of container C (shared, ordered, head-only visibility) and putting it in container D (player-specific, ordered, public tail-only visibility). The fact that you call A a deck, B a hand, C a supply pile and D the player discard pile is completely arbitrary. "in play" is a container, "set aside with Prince" is a container. The names and implications of each are all part of the configuration.
What do cards do? Well, they contain a sequence of instructions which must be followed in order, but even then, they're conditional. There are often several different instructions that are followed depending on which container the card is in. Some cards affect the game differently in different containers. Some instructions give the player a choice. Some simply add or subtract values from A, B, C, D, but even then, additions or subtractions need to be bounded (not less than zero?) or conditional (instruction is only followed if value F is greater than value G?)
And even the concept of a "card" may be too specific. Anything that can effect game state and can move between different containers needs to be tracked. Landmarks, events, adventures tokens, victory point tokens, etc., are all objects that move and affect game state and may contain instructions.
To say nothing of turn phases. Again, don't think about action/buy/cleanup. Think phase A, B, C, D, etc. Allow the configuration to specify what happens during each of these phases, whether it's optional or mandatory, how many times it can be repeated, etc. And keep in mind that the "what happens" part of these phases would allow setting, clearing or modifying the values described in the beginning. Different games have different phases. Many games draw one card at the start of turn. Dominion cleans up all cards from play and hand and draws a new hand at the end of the turn. These are just moving cards from one container to another during different phases and could be implemented in a sufficiently robust system.
If anything, exploring a generalized system like this will be a much more valuable programming and development experience than writing an implementation of a specific game.
Note: Starting as console-only is a good call. Writing a UI would be an unspeakable nightmare. If anything, what I'm describing above is kind of a game-development API which you (or someone else) could write a UI on top of for a specific game implementation. But again, maybe you want some API UI tools, as well, for implementing on-screen game object containers and manipulations.
AI, incidentally, is a lot harder than you think. I would keep that open and scriptable and just start with the concept of AI scripts, much like the Geronimoo sim, so that you could script AIs for pre-designed configurations. Making an AI that can handle any possible configuration, particularly if the system is sufficiently flexible and robust, is virtually impossible. However, if you allow specific AIs to be scripted, the you or others could create challenge games with a pre-configured game and AI that others could play against to see if they could beat it without reading the AI script.