#!/usr/bin/env python3 from __future__ import annotations import json from datetime import datetime, timezone from pathlib import Path ROOT = Path('/home/smlflg/Projekte/AgentProjectMinenraeumer/ProjectIntakeTower') PENDING = ROOT / 'jobs' / 'pending' DRAFTS = ROOT / 'github' / 'issue_drafts' TRIAGE = ROOT / 'triage' PENDING.mkdir(parents=True, exist_ok=True) DRAFTS.mkdir(parents=True, exist_ok=True) now = datetime.now(timezone.utc).replace(microsecond=0).isoformat() common_forbidden = [ 'modify source project files unless Samuel explicitly changes this contract', 'delete/archive/move source projects', 'commit', 'push', 'merge', 'read or print secrets', 'create GitHub issues', 'run dependency installs that write into source projects', ] def job(job_id, project_name, project_path, task_type, objective, extra_allowed, expected, verifier_commands, inputs=None, stop_extra=None, allowed_files_extra=None, mode='review_only'): outdir = f'jobs/done/{job_id}' return { 'job_id': job_id, 'project_name': project_name, 'project_path': project_path, 'mode': mode, 'task_type': task_type, 'objective': objective, 'allowed_actions': [ 'read non-secret files in allowed source paths', 'read ProjectIntakeTower inventory/evidence/triage files', 'write artifacts only inside ProjectIntakeTower/jobs/done//', ] + extra_allowed, 'forbidden_actions': common_forbidden, 'allowed_files': [ f'{project_path}/** read-only, excluding secrets and dependency/build/cache dirs', f'{ROOT}/inventory/** read-only', f'{ROOT}/triage/** read-only', f'{ROOT}/{outdir}/** write', ] + (allowed_files_extra or []), 'expected_artifacts': [f'{outdir}/{x}' for x in expected], 'required_artifacts': [f'{outdir}/{x}' for x in expected], 'verifier_commands': verifier_commands, 'verifier': {'type': 'command', 'command': verifier_commands[0] if verifier_commands else 'python3 verifier/verify_artifacts.py'}, 'stop_conditions': [ 'credentials required', 'write outside ProjectIntakeTower needed', 'destructive action needed', 'project ownership or intent unclear', 'secret-like file must be opened to proceed', ] + (stop_extra or []), 'scope': { 'allowed_paths': [project_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': inputs or {}, 'timeout_minutes': 45, 'max_iterations': 2, 'if_blocked': 'write status=needs_human in result.json and stop', 'rejoin_policy': 'summarize status, artifact_paths, verifier result, needs_human, next_action', 'created_by': 'operator_intake_command', 'created_at': now, } jobs = [ job( 'intake-audit-komandozentral', 'KomandoZentral', '/home/smlflg/Projekte/KomandoZentral', 'audit', 'Audit KomandoZentral read-only and produce an owner-facing audit: purpose, state, risks, verifier status, and one next action.', ['run non-destructive metadata/test discovery commands only if they do not mutate the repo'], ['result.json', 'audit.md'], ['python3 verifier/verify_artifacts.py --job jobs/pending/intake-audit-komandozentral.json --require-done'], {'project_card': 'inventory/project_cards/komandozentral-46af91fa1c.md', 'evidence_file': 'inventory/evidence/komandozentral-46af91fa1c.json'} ), job( 'intake-generate-tests-werbinich', 'WerBinIch', '/home/smlflg/Projekte/WerBinIch', 'test_design', 'Generate a test plan and ready-to-apply test patch for WerBinIch without editing the source repo.', ['inspect existing code/tests read-only', 'write proposed test files as patch/diff artifacts under ProjectIntakeTower only'], ['result.json', 'test_plan.md', 'proposed_tests.patch'], ['python3 verifier/verify_artifacts.py --job jobs/pending/intake-generate-tests-werbinich.json --require-done'], {'project_card': 'inventory/project_cards/werbinich-4b2f31741d.md', 'evidence_file': 'inventory/evidence/werbinich-4b2f31741d.json'}, stop_extra=['source repo test creation requires owner approval before applying patch'] ), job( 'intake-consolidate-agent-control-tower-repos', 'Agent Control Tower repos', '/home/smlflg/Projekte', 'consolidation_plan', 'Consolidate the Agent Control Tower family conceptually: map overlaps, pick system of record candidates, and propose merge/archive sequence. No repo edits.', ['compare related project cards/evidence', 'produce consolidation matrix and recommended owner decision tree'], ['result.json', 'consolidation_matrix.md', 'owner_decision_tree.md'], ['python3 verifier/verify_artifacts.py --job jobs/pending/intake-consolidate-agent-control-tower-repos.json --require-done'], { 'candidate_projects': [ 'Zentrale /home/smlflg/Projekte/Zentrale', 'KomandoZentral /home/smlflg/Projekte/KomandoZentral', 'ACT-agentcommandotower /home/smlflg/Projekte/ACT-agentcommandotower', 'AIOS-Cockpit /home/smlflg/Projekte/AIOS-Cockpit', 'MultiHarnessStudio /home/smlflg/Projekte/MultiHarnessStudio', 'FusionKomandoZentraleZentrale /home/smlflg/Projekte/FusionKomandoZentraleZentrale' ] }, allowed_files_extra=[ '/home/smlflg/Projekte/Zentrale/** read-only, excluding secrets and dependency/build/cache dirs', '/home/smlflg/Projekte/ACT-agentcommandotower/** read-only, excluding secrets and dependency/build/cache dirs', '/home/smlflg/Projekte/AIOS-Cockpit/** read-only, excluding secrets and dependency/build/cache dirs', '/home/smlflg/Projekte/MultiHarnessStudio/** read-only, excluding secrets and dependency/build/cache dirs', '/home/smlflg/Projekte/FusionKomandoZentraleZentrale/** read-only, excluding secrets and dependency/build/cache dirs', ] ), job( 'intake-archive-dead-prototype-xyz', 'XYZ prototype candidate', '/home/smlflg/Projekte', 'archive_review', 'Find the intended dead prototype XYZ candidate from inventory evidence and produce an archive recommendation. Do not move/delete/archive anything.', ['search inventory/project cards for XYZ-like candidates', 'write archive recommendation only'], ['result.json', 'archive_review.md'], ['python3 verifier/verify_artifacts.py --job jobs/pending/intake-archive-dead-prototype-xyz.json --require-done'], {'known_status': 'No exact project named XYZ found in current inventory search; human confirmation required before any archive action.'}, stop_extra=['exact XYZ target cannot be identified', 'archive/delete/move requested'] ), job( 'intake-build-verifier-hermes-profile-health', 'Hermes profile health', '/home/smlflg/.hermes/profiles', 'verify', 'Run and improve the ProjectIntakeTower Hermes profile health verifier; summarize unhealthy profiles and safe next actions.', ['run verifier/verify_hermes_profile_health.py', 'inspect report only; do not read .env/auth/token files'], ['result.json', 'hermes_profile_health_summary.md'], ['python3 verifier/verify_artifacts.py --job jobs/pending/intake-build-verifier-hermes-profile-health.json --require-done'], {'verifier_script': 'verifier/verify_hermes_profile_health.py', 'report': 'verifier/hermes_profile_health_report.json'}, allowed_files_extra=[f'{ROOT}/verifier/verify_hermes_profile_health.py read/write', f'{ROOT}/verifier/hermes_profile_health_report.json read/write'] ), ] for j in jobs: (PENDING / f"{j['job_id']}.json").write_text(json.dumps(j, ensure_ascii=False, indent=2), encoding='utf-8') draft = [ f"# [ProjectIntakeTower] {j['objective']}", '', '## Intake command', '', f"- Job: `{j['job_id']}`", f"- Project: `{j['project_name']}`", f"- Path/scope: `{j['project_path']}`", f"- Mode: `{j['mode']}`", '', '## Safety', '', '- Review-only by default.', '- No source project modifications.', '- No secrets, commits, pushes, deletes, or automatic issue creation.', '', '## Expected artifacts', '', ] for a in j['expected_artifacts']: draft.append(f'- `{a}`') draft += ['', '## Verifier', '', f"`{j['verifier']['command']}`", ''] (DRAFTS / f"{j['job_id']}.md").write_text('\n'.join(draft), encoding='utf-8') intake_md = TRIAGE / 'INTAKE_COMMANDS.md' intake_lines = ['# Intake Commands', '', f'Generated: {now}', '', '| Command | Job | Status | Human gate |', '|---|---|---|---|'] rows = [ ('Audit KommandoZentral', 'intake-audit-komandozentral', 'ready', 'no destructive action'), ('Generate tests for WerBinIch', 'intake-generate-tests-werbinich', 'ready as patch artifact', 'apply patch requires approval'), ('Consolidate Agent Control Tower repos', 'intake-consolidate-agent-control-tower-repos', 'ready', 'merge/archive decisions require approval'), ('Archive dead prototype XYZ', 'intake-archive-dead-prototype-xyz', 'needs_human target ambiguous', 'yes: exact XYZ target not found'), ('Build verifier for Hermes profile health', 'intake-build-verifier-hermes-profile-health', 'verifier script created; job ready', 'profile fixes require approval'), ] for cmd, jid, status, gate in rows: intake_lines.append(f'| {cmd} | `{jid}` | {status} | {gate} |') intake_md.write_text('\n'.join(intake_lines)+'\n', encoding='utf-8') owner = ROOT / 'OWNER_DIGEST.md' old = owner.read_text(encoding='utf-8') if owner.exists() else '# OWNER DIGEST\n' section = '\n## Explicit intake commands queued\n\n' + '\n'.join(f'- {cmd}: `jobs/pending/{jid}.json` — {status}' for cmd, jid, status, gate in rows) + '\n' if '## Explicit intake commands queued' in old: old = old.split('## Explicit intake commands queued')[0].rstrip() + section else: old = old.rstrip() + '\n' + section owner.write_text(old, encoding='utf-8') print(json.dumps({'status':'succeeded','jobs_written':len(jobs),'drafts_written':len(jobs),'intake_commands':str(intake_md.relative_to(ROOT))}, indent=2))