Add timestamp-based history to your Prompt Vault — without breaking anything that already works. This is how real features get built.
Day 24 of 80
Every time a prompt is generated, log it. You want to know: when did it happen, what shot was requested, which platform, what did Claude say, did it get saved. All of this goes into history.json — a running record you can browse any time.
You're adding this feature to the project from Day 23. The goal is to add it cleanly: two new functions in helpers.py, one new menu option in vault.py, and one new call inside generate_prompt(). Everything else stays unchanged.
load_history(), log_generation(), show_history()log_generation() after each generation, add "View history" to the menuOpen helpers.py and add the following. First, add the datetime import at the top of the file (after the existing import json):
import json
from datetime import datetime # ADD THIS LINE
PROMPTS_FILE = "prompts.json"
HISTORY_FILE = "history.json" # ADD THIS LINE
VALID_PLATFORMS = ["Kling", "Runway", "Veo"]
from datetime import datetime: Python's datetime module contains many time-related classes. You specifically want the datetime class inside it. This is the standard pattern: from module import ClassName.
HISTORY_FILE = "history.json": Same pattern as PROMPTS_FILE — define the filename once at the top so it's easy to change later.
Now add the three new functions at the bottom of helpers.py:
def load_history():
"""Load generation history. Returns empty list if no history yet."""
try:
with open(HISTORY_FILE, "r") as f:
return json.load(f)
except FileNotFoundError:
return []
def log_generation(shot, platform, prompt, saved):
"""Append one generation event to the history file."""
history = load_history()
history.append({
"timestamp": datetime.now().isoformat(),
"shot": shot,
"platform": platform,
"prompt": prompt[:80],
"saved": saved,
})
with open(HISTORY_FILE, "w") as f:
json.dump(history, f, indent=2)
def show_history():
"""Print the 10 most recent generation events, newest first."""
history = load_history()
if not history:
print(" No history yet.\n")
return
recent = list(reversed(history[-10:]))
print(f"\n--- Recent History (last {len(recent)}) ---\n")
for entry in recent:
date, time = entry["timestamp"].split("T")
time = time[:5]
status = "saved" if entry["saved"] else "skipped"
print(f" [{date} {time}] [{entry['platform']}] {entry['shot']}")
print(f" {entry['prompt'][:60]}... ({status})\n")
load_history() (lines 1–7): Identical pattern to load_prompts(). The try/except means the first time you run the app (before any history exists), it silently returns an empty list instead of crashing.
log_generation() (lines 10–20): Takes four arguments — the shot description, platform, the full generated prompt, and whether the user saved it (a boolean: True or False).
Line 13 — datetime.now().isoformat(): datetime.now() returns the current date and time. .isoformat() converts it to a string in the standard format: "2026-04-06T14:32:05.123456". ISO format is sortable as a string, which makes it perfect for logs.
Line 16 — prompt[:80]: Truncate the prompt to 80 characters for storage. The full prompt can be very long; you only need enough to recognize it in the history view.
Line 17 — "saved": saved: Stores the boolean directly. In JSON this becomes true or false (lowercase).
show_history() (lines 23–35): Shows the 10 most recent entries in reverse order (newest first).
Line 29 — history[-10:]: Slice the last 10 items. Then reversed() flips them so the most recent appears at the top. Wrap in list() because reversed() returns an iterator, not a list.
Lines 31–32 — splitting the timestamp: "2026-04-06T14:32:05".split("T") returns ["2026-04-06", "14:32:05"]. You unpack that into date and time. Then time[:5] trims it to "14:32" — no seconds needed in the display.
Line 33 — inline conditional: "saved" if entry["saved"] else "skipped" is a ternary expression — Python's one-line if/else. It reads like English.
Two changes in vault.py. First, update the import line:
from helpers import load_prompts, save_prompts, validate_platform, log_generation, show_history
Just add log_generation and show_history to the existing import list. Python imports exactly what you name — nothing more.
Second, call log_generation() at the end of generate_prompt(), right after the save decision:
save_it = input(" Save this prompt? (y/n): ").strip().lower()
did_save = False
if save_it == "y":
prompts = load_prompts()
prompts.append({"shot": shot, "platform": platform, "prompt": prompt_text})
save_prompts(prompts)
print(" Saved.\n")
did_save = True
log_generation(shot, platform, prompt_text, did_save)
Lines 2 and 8: did_save is a boolean flag that starts as False and becomes True only if the user confirmed saving. This is cleaner than checking save_it == "y" again inside the log call.
Line 9: log_generation() is called regardless of whether the user saved. You want a record of every generation, not just the ones that got saved. That's what makes the history useful — you can look back at prompts you skipped.
Third, add "View history" to the menu in main():
def main():
print("\n=== DVP Prompt Vault ===\n")
while True:
print(" 1. View saved prompts")
print(" 2. Generate new prompt")
print(" 3. View history")
print(" 4. Quit")
choice = input("\n Choose: ").strip()
if choice == "1":
show_prompts()
elif choice == "2":
generate_prompt()
elif choice == "3":
show_history()
elif choice == "4":
print(" Bye.\n")
break
else:
print(" Type 1, 2, 3, or 4.\n")
Only two real additions: print(" 3. View history"), the elif choice == "3": show_history() branch, and bumping Quit to option 4. The structure of the while loop is identical to before — you're extending it, not rewriting it.
This is what "adding a feature without breaking what works" looks like. You touched three lines in vault.py and added three functions to helpers.py. Everything that existed before still runs exactly as it did.
--- Recent History (last 3) ---
[2026-04-06 14:45] [Kling] Aerial drone shot over golf course
Cinematic wide-angle drone footage soaring over an emerald golf... (saved)
[2026-04-06 14:38] [Runway] Slow-motion club impact
Ultra slow-motion capture of club face striking ball at moment... (skipped)
[2026-04-06 14:21] [Veo] Tracking shot following the ball
Cinematic tracking shot locked onto the golf ball from the tee... (saved)
After running the vault and generating a few prompts, open history.json in VS Code. You'll see a JSON array where each object has timestamp, shot, platform, prompt, and saved. This is raw data — not just for display. Next week's Flask app could serve this data to a browser as an API response with two lines of code.
90% of professional software development is exactly what you did today: add a feature to existing code without breaking what already works. You didn't rewrite the vault. You didn't touch show_prompts(). You added functions, extended the import line, called a new function in one place, and added one menu option. The existing tests (your manual testing from Day 23) still pass. That discipline — add, don't break — is the thing senior developers mean when they say "clean code."
from datetime import datetime and HISTORY_FILE to the top of helpers.pyload_history(), log_generation(), and show_history() to helpers.pyvault.py to include the new functionslog_generation() after every prompt generation in vault.pyhistory.json directly and verified the timestamps and data look correctTomorrow is a reflection day. You'll review everything you built this week, do a milestone check against four specific skills, and get a preview of Week 6 where you turn this command-line vault into a web app using Flask. No new code — just making sure everything landed before you move forward.