import argparse
import json
import os
import sys
from datetime import datetime
from pathlib import Path
ENGINEERING_DIR = Path(__file__).parent.parent / "engineering"
TEMPLATE = """
{
"subject": "<Brief title of the engineering work>",
"achievement": "<What was accomplished - be specific about code changes, metrics, etc.>",
"rationale": "<Why this change matters - link to research, performance gains, architectural benefits>",
"tags": ["<optional>", "<tags>", "<for-categorization>"],
"related_files": ["<optional>", "<list of modified files>"],
"metrics": {
"before": "<optional: metric before change>",
"after": "<optional: metric after change>"
},
"references": ["<optional: papers, docs, or prior logs>"],
"next_steps": ["<optional: follow-up work identified>"]
}
"""
def generate_log(data: dict) -> str:
now = datetime.now()
timestamp = now.strftime("%Y-%m-%d %H:%M:%S")
date_str = now.strftime("%Y-%m-%d")
subject = data.get("subject", "Untitled")
achievement = data.get("achievement", "")
rationale = data.get("rationale", "")
tags = data.get("tags", [])
related_files = data.get("related_files", [])
metrics = data.get("metrics", {})
references = data.get("references", [])
next_steps = data.get("next_steps", [])
conclusions = data.get("conclusions", [])
commits = data.get("commits", [])
md = f"""# {subject}
**Date:** {date_str}
**Timestamp:** {timestamp}
"""
if tags:
md += f"**Tags:** {', '.join(tags)}\n"
if commits:
md += f"**Commits:** {', '.join(f'`{c}`' for c in commits)}\n"
md += f"""
---
## Achievement
{achievement}
## Rationale
{rationale}
"""
if metrics:
md += "\n## Metrics\n\n"
top_metrics = ["params", "epochs", "wall_clock", "accuracy", "failure_mode", "delta"]
has_top = any(metrics.get(m) for m in top_metrics)
if has_top:
md += "| Metric | Value |\n|--------|-------|\n"
if metrics.get("params"):
md += f"| Parameters | {metrics['params']} |\n"
if metrics.get("epochs"):
md += f"| Epochs | {metrics['epochs']} |\n"
if metrics.get("wall_clock"):
md += f"| Wall Clock | {metrics['wall_clock']} |\n"
if metrics.get("accuracy"):
md += f"| Accuracy | {metrics['accuracy']} |\n"
if metrics.get("failure_mode"):
md += f"| Failure Mode | {metrics['failure_mode']} |\n"
if metrics.get("delta"):
md += f"| **Delta** | **{metrics['delta']}** |\n"
md += "\n"
before = metrics.get("before", {})
after = metrics.get("after", {})
if before or after:
md += "### Before/After Comparison\n\n"
md += "| Metric | Before | After |\n|--------|--------|-------|\n"
if isinstance(before, dict) and isinstance(after, dict):
all_keys = set(before.keys()) | set(after.keys())
for key in sorted(all_keys):
b_val = before.get(key, "N/A")
a_val = after.get(key, "N/A")
md += f"| {key} | {b_val} | {a_val} |\n"
else:
md += f"| Value | {before} | {after} |\n"
if conclusions:
md += "\n## Conclusions\n\n"
for i, conclusion in enumerate(conclusions, 1):
md += f"{i}. {conclusion}\n"
if related_files:
md += "\n## Related Files\n\n"
for f in related_files:
md += f"- `{f}`\n"
if references:
md += "\n## References\n\n"
for ref in references:
md += f"- {ref}\n"
if next_steps:
md += "\n## Next Steps\n\n"
for step in next_steps:
md += f"- [ ] {step}\n"
md += "\n---\n*Generated by eng_log.py*\n"
return md
def save_log(content: str, subject: str) -> Path:
ENGINEERING_DIR.mkdir(exist_ok=True)
now = datetime.now()
date_prefix = now.strftime("%Y%m%d")
time_suffix = now.strftime("%H%M%S")
safe_subject = "".join(c if c.isalnum() or c in "-_ " else "" for c in subject)
safe_subject = safe_subject.replace(" ", "-").lower()[:50]
filename = f"{date_prefix}-{time_suffix}-{safe_subject}.md"
filepath = ENGINEERING_DIR / filename
filepath.write_text(content, encoding="utf-8")
return filepath
def main():
parser = argparse.ArgumentParser(description="Generate engineering log entries")
parser.add_argument("--subject", "-s", help="Subject/title of the log entry")
parser.add_argument("--achievement", "-a", help="What was achieved")
parser.add_argument("--rationale", "-r", help="Why this matters")
parser.add_argument("--tags", "-t", nargs="*", help="Optional tags")
parser.add_argument("--from-stdin", action="store_true", help="Read JSON from stdin")
parser.add_argument("--template", action="store_true", help="Print template JSON")
parser.add_argument("--dry-run", action="store_true", help="Print markdown without saving")
args = parser.parse_args()
if args.template:
print("Engineering Log Template (JSON):")
print(TEMPLATE)
return
if args.from_stdin:
try:
data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error parsing JSON: {e}", file=sys.stderr)
sys.exit(1)
elif args.subject and args.achievement:
data = {
"subject": args.subject,
"achievement": args.achievement,
"rationale": args.rationale or "",
"tags": args.tags or []
}
else:
parser.print_help()
print("\nError: Provide --subject and --achievement, or use --from-stdin", file=sys.stderr)
sys.exit(1)
content = generate_log(data)
if args.dry_run:
print(content)
else:
filepath = save_log(content, data.get("subject", "log"))
print(f"Log saved to: {filepath}")
if __name__ == "__main__":
main()