"""Command line: build / verify / render / nonce.""" from __future__ import annotations import argparse import json import sys from .build import build_cv from .verify import verify_cv, all_verified from .render import render_markdown from .model import CV from .proof import make_nonce def _load_externals(path): if not path: return [] with open(path) as f: data = json.load(f) return data if isinstance(data, list) else data.get("externals", []) def cmd_build(args): externals = _load_externals(args.externals) cv = build_cv(args.agent, externals, gridmolt_base=args.gridmolt) out = cv.to_json() if args.out: with open(args.out, "w") as f: f.write(out + "\n") print(f"wrote {args.out} — verified total {cv.verified_total()}") else: print(out) def cmd_verify(args): cv = CV.from_json(open(args.cv).read()) results = verify_cv(cv) for r in results: print(f"[{r['status']:>16}] {r['platform']}:{r['handle']} " f"karma={r['claimed_karma']}" + (f" ({'; '.join(r['notes'])})" if r.get("notes") else "")) ok = all_verified(results) print("\nOK" if ok else "\nFAILED — at least one verified claim did not re-check") sys.exit(0 if ok else 1) def cmd_render(args): cv = CV.from_json(open(args.cv).read()) md = render_markdown(cv) if args.out: with open(args.out, "w") as f: f.write(md) print(f"wrote {args.out}") else: print(md) def cmd_nonce(args): nonce = make_nonce(args.agent, args.platform) print(nonce) print(f"\nPost the line above publicly on {args.platform} as '{args.agent}', then " f"put the post URL in your externals config as proof.url.", file=sys.stderr) def main(argv=None): p = argparse.ArgumentParser(prog="agent-cv", description="Verifiable, cross-platform CV for AI agents.") sub = p.add_subparsers(dest="cmd", required=True) b = sub.add_parser("build", help="build a CV (gridmolt verified + externals)") b.add_argument("--agent", required=True) b.add_argument("--externals", help="JSON file: list of external accounts") b.add_argument("--gridmolt", default="https://gridmolt.org") b.add_argument("--out") b.set_defaults(func=cmd_build) v = sub.add_parser("verify", help="re-verify a CV by re-fetching its sources") v.add_argument("cv") v.set_defaults(func=cmd_verify) r = sub.add_parser("render", help="render a CV to Markdown") r.add_argument("cv") r.add_argument("--out") r.set_defaults(func=cmd_render) n = sub.add_parser("nonce", help="mint an account-linking nonce to post elsewhere") n.add_argument("--agent", required=True) n.add_argument("--platform", required=True) n.set_defaults(func=cmd_nonce) args = p.parse_args(argv) args.func(args) if __name__ == "__main__": main()