#!/usr/bin/env python3 from intake_common import * def job_for(p): pid = p["project_id"] job_id = f"pit-{pid}-review" outdir = f"jobs/done/{job_id}" return { "job_id": job_id, "project_name": p["name"], "project_path": p["path"], "mode": "review_only", "task_type": "review", "objective": f"Read-only handoff for {p['name']}: collapse open mental tabs into one verified next action.", "allowed_actions": [ "read non-secret project files", "read ProjectIntakeTower evidence and project card", "run non-destructive metadata commands only when needed", "write result artifacts inside ProjectIntakeTower/jobs/done// only", ], "forbidden_actions": [ "modify project files", "delete files", "commit", "push", "merge", "read or print secrets", "create GitHub issues", "run dependency installs or build steps that write into the project", ], "allowed_files": [ f"{p['path']}/** read-only, excluding secrets and ignored dependency/build directories", f"{str(ROOT)}/inventory/project_cards/{pid}.md read-only", f"{str(ROOT)}/{p.get('evidence_file')} read-only", f"{str(ROOT)}/{outdir}/** write", ], "expected_artifacts": [ f"{outdir}/result.json", f"{outdir}/handoff.md", ], "required_artifacts": [ f"{outdir}/result.json", f"{outdir}/handoff.md", ], "verifier_commands": [ f"python3 verifier/verify_artifacts.py --job jobs/pending/{job_id}.json --require-done" ], "verifier": {"type": "command", "command": f"python3 verifier/verify_artifacts.py --job jobs/pending/{job_id}.json --require-done"}, "stop_conditions": [ "credentials required", "write outside ProjectIntakeTower needed", "destructive action needed", "project ownership or intent unclear", "secret-like file must be opened to proceed", ], "scope": { "allowed_paths": [p["path"], str(ROOT)], "allowed_tools": ["read_file", "search_files", "terminal", "write_file"], "allowed_actions": ["read-only inspection", "write handoff artifacts under ProjectIntakeTower/jobs/done"], "forbidden_actions": ["modify source project", "commit", "push", "merge", "delete", "read secrets", "create issues"], }, "inputs": { "project_card": f"inventory/project_cards/{pid}.md", "evidence_file": p.get("evidence_file"), "triage_status": p.get("triage_status"), "score": p.get("score"), }, "timeout_minutes": 30, "max_iterations": 2, "if_blocked": "write status=needs_human in result.json and stop", "rejoin_policy": "summarize status, changed_files, artifact_paths, verifier result, needs_human, next_action", } def main(): ensure_dirs() # Pending contracts are generated artifacts owned by this harness; clear stale v0 contracts before writing v1. for old in PENDING.glob("*.json"): old.unlink() projects = sorted(load_jsonl(INV / "projects.jsonl"), key=project_sort_key) selected = [p for p in projects if p.get("triage_status") in {"needs_human", "active", "quick_win", "review"}] if len(selected) < min(20, len(projects)): selected = projects[:min(40, len(projects))] else: selected = selected[:40] for p in selected: job = job_for(p) (PENDING / f"{job['job_id']}.json").write_text(json.dumps(job, ensure_ascii=False, indent=2), encoding="utf-8") print(json.dumps({"status": "succeeded", "jobs_pending_written": len(selected)}, indent=2)) if __name__ == "__main__": main()