diff --git a/README.md b/README.md index b19f49c..206c596 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # AI Automations Intelligent AI automations using the Bito CLI and other tools. Please use them or customize them to your needs! -Four intelligent automations are available currently: +Five intelligent automations are available currently: ## [Documentation](https://github.com/gitbito/AI-Automation/tree/main/documentation/) Several different automations. Provide Bito CLI a directory and it will automatically provide a detailed overview, visualization, and documentation for each file including summary of the file, dependencies, documentation regarding class/modules, function/methods, etc. Works in over 50+ programming languages, and documentation can be generated in over 50 spoken languages (English, German, Chinese, etc). @@ -18,6 +18,11 @@ This Python script uses the Bito CLI to generate release notes based on the diff ## [Generate Commit Messages](https://github.com/gitbito/AI-Automation/tree/main/git/commit_msg) Generate commit messages given a repo path. + + +## [Objective Data Manager](./operations/objective_data_manager) +Build and maintain an objective-focused datastore that tracks permissions, submissions, government-guaranteed lending records, a full file inventory (size, timestamps, hashes), linked file placement plans, and progressive execution steps. Useful for organizing execution data, exporting all records, and proving what was submitted and when. + ## Prerequisites Bito CLI, available [here](https://github.com/gitbito/CLI). diff --git a/operations/objective_data_manager/README.md b/operations/objective_data_manager/README.md new file mode 100644 index 0000000..6805ff6 --- /dev/null +++ b/operations/objective_data_manager/README.md @@ -0,0 +1,42 @@ +# Objective Data Manager + +A lightweight CLI to collect and maintain the data needed to execute objectives: + +- objective definitions +- permission/authorization records +- submission tracking +- government guarantee lending records +- full file inventory (name, size, modified time, hash) +- file-to-objective linking for situation-specific placement +- complete data export (`get-all-data`) +- progressive execution steps for acceleration (`add-execution-step`) +- authority and control matrix records (`add-control-matrix`) + +## Usage + +From the repository root: + +```bash +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-objective --id OBJ-001 --summary "Organize and execute submissions" --owner "Operations" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-permission --objective OBJ-001 --granted-by "Agency" --scope "Submit on behalf of org" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-submission --objective OBJ-001 --title "Q2 filing" --status "in_progress" --destination "Portal" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-lending-item --objective OBJ-001 --borrower "Small Business A" --amount 250000 --guarantee-type "SBA 7(a)" --status "pending" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-execution-step --objective OBJ-001 --step-id STEP-01 --title "Prepare submission package" --status "in_progress" --priority 10 +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-execution-step --objective OBJ-001 --step-id STEP-02 --title "Submit through authorized portal" --status "pending" --priority 20 +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json update-step-status --objective OBJ-001 --step-id STEP-02 --status "in_progress" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json add-control-matrix --pon "1984" --tas "Authorized" --approval-authority "Program Office" --execution-systems "Authorized Treasury systems" --custody "Regulated financial institutions" --oversight "Treasury, OMB, GAO" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json index-files --root . +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json link-file --objective OBJ-001 --file-path "docs/filings/Q2.pdf" --situation "Quarterly filing" --target-location "submissions/quarterly" --notes "Upload first" +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json organize-plan --objective OBJ-001 +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json get-all-data +python3 operations/objective_data_manager/objective_data_manager.py --store objective_data.json summary +``` + +## Notes + +- Run `index-files` whenever your working files change and you need a refreshed inventory. +- Use `link-file` to map files to objective situations and target placement locations. +- Use `organize-plan` to produce a grouped placement plan by `target_location`. +- Use `add-execution-step` + `update-step-status` to drive progressive action plans and track active execution. +- Use `add-control-matrix` to preserve authority/control metadata for compliance evidence. +- The datastore is plain JSON so it can be reviewed, versioned, or synced into a larger workflow. diff --git a/operations/objective_data_manager/government_guarantee_packet/00_Governance/data_dictionary.md b/operations/objective_data_manager/government_guarantee_packet/00_Governance/data_dictionary.md new file mode 100644 index 0000000..01bf912 --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/00_Governance/data_dictionary.md @@ -0,0 +1,9 @@ +# Data Dictionary + +- `record_id`: Permanent unique identifier for each record. +- `source_file`: Original intake artifact (unaltered). +- `structured_data`: JSON extraction from source. +- `verification_artifact`: Evidence of authenticity and signer validation. +- `control_evidence`: Proof of compliance and policy execution. +- `submission_packet`: Final assembled files ready for submission. +- `audit_package`: Full lifecycle evidence archive. diff --git a/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/approvals_log.csv b/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/approvals_log.csv new file mode 100644 index 0000000..3d0545c --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/approvals_log.csv @@ -0,0 +1,5 @@ +approval_id,record_id,approval_stage,approver_name,approver_role,status,decision_date,notes +A-001,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Authenticity,[],Compliance Lead,Pending,, +A-002,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Legal Review,[],Counsel,Pending,, +A-003,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Compliance Signoff,[],Compliance Director,Pending,, +A-004,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Submission Authorization,[],Program Director,Pending,, diff --git a/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/submission_register.csv b/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/submission_register.csv new file mode 100644 index 0000000..184583f --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/01_Master_Index/submission_register.csv @@ -0,0 +1,2 @@ +record_id,date_received,agency,office,program,counterparty,document_type,subject,signature_validated,attachments_complete,trigger_event_required,trigger_event_date,deadline_rule,computed_due_date,owner,legal_status,compliance_status,risk_level,current_status,next_action,evidence_path,last_updated +TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,2025-08-28,United States Department of the Treasury,CDFI Programs,Certified CDFI programs,SNAPPCREDITCOM (Non-Profit),Agency Letter,Acceptance of Treasury Bond Pledge for Triggered Guarantees,N,N,Y,,+60 days from realized payout,,Primary Owner,Pending,Pending,Medium,Received,Verify authenticity and collect attachments,02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM,2026-04-08 diff --git a/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/02_Extracted/treasury_letter_structured_data.json b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/02_Extracted/treasury_letter_structured_data.json new file mode 100644 index 0000000..48ee32d --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/02_Extracted/treasury_letter_structured_data.json @@ -0,0 +1,31 @@ +{ + "record_id": "TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE", + "document_type": "Government Agency Letter", + "agency_name": "United States Department of the Treasury", + "agency_address": "1500 Pennsylvania Avenue NW, Washington, D.C. 20220", + "document_date_iso": "2025-08-28", + "recipient": { + "organization": "SNAPPCREDITCOM (Non-Profit)", + "care_of": "Enzo Caprelli", + "address": "700 E Lake Dr, Unit 11, Orange, CA 92866-2732" + }, + "subject": "Acceptance of Treasury Bond Pledge for Triggered Guarantees", + "key_terms": [ + "Treasury accepts pledge of U.S. Treasury bonds.", + "Face value equals outstanding loan amounts for triggered guarantees.", + "Bonds may be held or banked until maturity.", + "Bond attachment information due within 60 days of any realized payout.", + "Treasury incurs no loss and obligations remain fully secured." + ], + "signatory": { + "name": "Jane M. Thornton", + "title": "Director, CDFI Programs" + }, + "signature_status": "Placeholder observed in provided image", + "cc": [ + "Office of Financial Institutions, Treasury Department" + ], + "attachments_mentioned": [ + "Supporting documents describing the general guarantee framework and project outlines" + ] +} diff --git a/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/03_Verification/authenticity_check_notes.md b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/03_Verification/authenticity_check_notes.md new file mode 100644 index 0000000..2f8d965 --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/03_Verification/authenticity_check_notes.md @@ -0,0 +1,22 @@ +# Authenticity Check Notes + +- Record ID: TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE +- Date opened: 2026-04-08 +- Analyst: [Name] + +## Checks Performed +1. Agency address format check +2. Signatory identity check +3. Official contact callback/email confirmation +4. Letter metadata consistency +5. Signature status check + +## Findings +- [ ] Confirmed authentic +- [ ] Pending confirmation +- [ ] Inconsistent indicators found + +## Signature Review +- Observed text: [Signature Placeholder] +- Executed signature present? [Yes/No] +- Action taken: [Describe] diff --git a/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/compliance_checklist.md b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/compliance_checklist.md new file mode 100644 index 0000000..02ee62c --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/compliance_checklist.md @@ -0,0 +1,25 @@ +# Compliance Checklist — Treasury Bond Pledge Acceptance + +## Document Identity +- [ ] Record ID assigned +- [ ] Source file preserved (unaltered) +- [ ] OCR/transcription completed +- [ ] Structured data file created + +## Authenticity +- [ ] Issuing agency verified via official channel +- [ ] Sender identity verified +- [ ] Signature validated (or executed copy requested) +- [ ] Verification evidence logged + +## Terms Validation +- [ ] Coverage term confirmed (face value = outstanding triggered amounts) +- [ ] Holding/banking-until-maturity term confirmed +- [ ] 60-day reporting requirement captured +- [ ] No-loss / fully-secured obligation captured + +## Operational Readiness +- [ ] Trigger event defined (realized payout) +- [ ] Due-date rule configured (+60 days) +- [ ] Reminder schedule configured (D+30, D+45, D+55, D+60) +- [ ] Responsible owner assigned diff --git a/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/policy_mapping.csv b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/policy_mapping.csv new file mode 100644 index 0000000..91e0516 --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/04_Legal_Compliance/policy_mapping.csv @@ -0,0 +1,6 @@ +clause_id,document_clause,control_owner,control_action,evidence_required,frequency,status +C-001,Treasury accepts pledge of U.S. Treasury bonds,Legal,Validate acceptance language and enforceability,Legal memo + review notes,One-time,Open +C-002,Face value equals outstanding triggered loan amounts,Finance,Reconcile pledge values to outstanding balances,Reconciliation workbook + signoff,Per trigger event,Open +C-003,Bonds may be held or banked until maturity,Treasury Ops,Track custody/holding records,Custody statements,Monthly,Open +C-004,Bond attachment information due within 60 days of realized payout,Compliance,Monitor payout events and deadline submissions,Submission receipt + timestamp,Per payout event,Open +C-005,Treasury incurs no loss / obligations fully secured,Risk,Validate collateral sufficiency and guarantee conditions,Risk assessment report,Per trigger event,Open diff --git a/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/06_Actions/task_tracker.csv b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/06_Actions/task_tracker.csv new file mode 100644 index 0000000..f2ff3de --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/02_Agency_Correspondence/Treasury/2025/2025-08-28_Treasury_AcceptanceBondPledge_SNAPPCREDITCOM/06_Actions/task_tracker.csv @@ -0,0 +1,4 @@ +task_id,record_id,task_name,task_description,owner,priority,status,start_date,due_date,completed_date,dependencies,evidence_file +T-001,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Verify authenticity,Confirm issuer and document legitimacy via official Treasury channel,Compliance Lead,High,Open,2026-04-08,2026-04-10,,None,03_Verification/authenticity_check_notes.md +T-002,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Obtain final signed copy,Request executed signed version if placeholder copy only,Legal Lead,High,Open,2026-04-08,2026-04-12,,T-001,03_Verification/signature_validation_log.csv +T-003,TREASURY-2025-08-28-SNAPPCREDITCOM-ACCEPTANCE,Collect referenced attachments,Obtain guarantee framework and project outline attachments,Operations Lead,High,Open,2026-04-08,2026-04-11,,T-001,05_Attachments_Referenced/ diff --git a/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/auto_charge_and_collateral_security_agreement.md b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/auto_charge_and_collateral_security_agreement.md new file mode 100644 index 0000000..264859e --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/auto_charge_and_collateral_security_agreement.md @@ -0,0 +1,70 @@ +# AUTO CHARGE AND COLLATERAL SECURITY AGREEMENT + +This Auto Charge and Collateral Security Agreement ("Agreement") is made effective as of [Effective Date], by and between [Secured Party Legal Name] ("Secured Party") and [Borrower Legal Name] ("Borrower"). + +## 1. Definitions +- **Obligations**: All debts, liabilities, and payment obligations under the Loan Documents. +- **Collateral**: All assets described in this Agreement and any proceeds of those assets. +- **Designated Accounts**: Deposit and investment accounts identified in Schedule A. +- **Collateral Accounts**: Accounts and assets identified in Schedule B. +- **Trigger Event**: Any event described in Section 5. + +## 2. Grant of Security Interest +Borrower grants Secured Party a continuing security interest in the Collateral, including Designated Accounts, Collateral Accounts, and all related proceeds, to secure all Obligations. + +## 3. Auto Charge Authorization +Borrower authorizes Secured Party to initiate ACH debits, wire transfers, account sweeps, and other charge mechanisms permitted under applicable law for amounts due under the Loan Documents. + +## 4. Payment Waterfall +1. Costs, fees, and expenses +2. Accrued interest +3. Past-due principal +4. Current principal +5. Reserve and guarantee reimbursement +6. Other Obligations + +## 5. Trigger Events +- Scheduled payment due dates +- Missed payment beyond the agreed grace period +- Breach of affirmative or negative covenants +- Cross-default under other loan or guarantee agreements +- Insolvency, bankruptcy, or similar event +- Guarantee payout or reimbursement event +- Execution of the Agreement by Borrower + +## 6. Notice +Secured Party will provide Borrower notice of any post-charge activity within [60] business days, unless a shorter or longer period is required by applicable law. + +## 7. Borrower Covenants +Borrower agrees to maintain active accounts, keep sufficient balances, and execute any additional documents necessary to perfect and maintain Secured Party's security interest. + +## 8. Perfection and Control +Borrower authorizes Secured Party to file UCC financing statements and execute control agreements or other perfection documents as required. + +## 9. Setoff +Secured Party may exercise any setoff rights permitted by applicable law against Borrower accounts and Collateral. + +## 10. Governing Law and Venue +Governing law: [State]. Venue: [County/State/Federal District]. + +## 11. Signature Blocks +The parties agree to execute signature blocks for: +- Secured Party authorized signatory +- Borrower authorized signatory + +## Schedule A — Designated Deposit Accounts +| Bank | Account Title | Last 4 | Routing | Method | Frequency | Limit | +|---|---|---:|---|---|---|---| +| [Bank Name] | [Account Title] | [Last 4] | [Routing Number] | [ACH/Wire/Sweep] | [Frequency] | [Limit] | + +## Schedule B — Collateral Accounts +| Custodian | Account ID | Asset Type | Control Agreement | Lien Priority | Notes | +|---|---|---|---|---|---| +| [Custodian] | [Account ID] | [Asset Type] | [Executed/Pending] | [1st/2nd] | [Notes] | + +## Schedule C — Trigger Matrix +| Trigger | Evidence | Approval | Notice | Owner | +|---|---|---|---|---| +| Scheduled Payment | Payment schedule | Automatic | [Notice Timing] | [Owner] | +| Default | Delinquency report | [Approver] | Within [X] days | [Owner] | +| Guarantee Payout | Payout report | [Approver] | Within [X] days | [Owner] | diff --git a/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/borrower_authorization_certificate.md b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/borrower_authorization_certificate.md new file mode 100644 index 0000000..8594bd1 --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/borrower_authorization_certificate.md @@ -0,0 +1,22 @@ +# Borrower Authorization Certificate + +I, [Name], as [Title] of [Borrower Legal Name], hereby certify that: + +1. I am duly authorized to execute the Auto Charge and Collateral Security Agreement on behalf of [Borrower Legal Name]. +2. The governing body of [Borrower Legal Name] has duly approved the Agreement on [Approval Date]. +3. The account and collateral schedules attached to the Agreement are true, complete, and correct to the best of my knowledge. +4. I have full authority to bind [Borrower Legal Name] with respect to all obligations and representations made in the Agreement. + +Signature: _______________________________ + +Name: [Name] +Title: [Title] +Date: _______________________________ + +Witness: + +Signature: _______________________________ + +Name: [Witness Name] +Title: [Witness Title] +Date: _______________________________ diff --git a/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/notice_addresses.md b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/notice_addresses.md new file mode 100644 index 0000000..91b3622 --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/notice_addresses.md @@ -0,0 +1,15 @@ +# Notice Addresses + +## Secured Party Notices +- Name/Department: [Secured Party Name] / [Department] +- Email: [securedparty@example.com] +- Address: [Street Address] +- City/State/ZIP: [City, State ZIP] +- Phone: [Phone Number] + +## Borrower Notices +- Name/Department: [Borrower Legal Name] / [Department] +- Email: [borrower@example.com] +- Address: [Street Address] +- City/State/ZIP: [City, State ZIP] +- Phone: [Phone Number] diff --git a/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/pdf_packet_manifest.md b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/pdf_packet_manifest.md new file mode 100644 index 0000000..a1506cd --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/03_Agreements/templates/pdf_packet_manifest.md @@ -0,0 +1,12 @@ +# PDF Packet Manifest (Assembly Order) + +1. Cover page (record ID, date, parties) +2. Auto Charge and Collateral Security Agreement (full text) +3. Schedule A — Designated Deposit Accounts +4. Schedule B — Collateral Accounts +5. Schedule C — Trigger Matrix +6. Borrower Authorization Certificate +7. Notice Addresses +8. Signature Pages +9. Control Agreements (DACA/SACA), if applicable +10. UCC filing copies, if applicable diff --git a/operations/objective_data_manager/government_guarantee_packet/README.md b/operations/objective_data_manager/government_guarantee_packet/README.md new file mode 100644 index 0000000..370d2fa --- /dev/null +++ b/operations/objective_data_manager/government_guarantee_packet/README.md @@ -0,0 +1,14 @@ +# Government Guarantee Lending Document Packet + +This folder contains a ready-to-use packet for organizing submissions related to collateralized lending and government-guarantee workflows. + +## Included +- Master indexes and trackers (`01_Master_Index`). +- Extracted source document records for the August 28, 2025 Treasury letter (`02_Agency_Correspondence/...`). +- Legal/compliance checklists and policy mappings. +- A full Auto Charge and Collateral Security Agreement template packet (`03_Agreements/templates`). + +## Notes +- Replace all bracketed placeholders before execution. +- Validate all legal language with licensed counsel. +- Treat any unsigned or placeholder-signature documents as unverified until authenticated. diff --git a/operations/objective_data_manager/objective_data_manager.py b/operations/objective_data_manager/objective_data_manager.py new file mode 100644 index 0000000..45b7fb2 --- /dev/null +++ b/operations/objective_data_manager/objective_data_manager.py @@ -0,0 +1,517 @@ +#!/usr/bin/env python3 +"""Objective data manager. + +Builds a local index of files and tracks objectives, permissions, submissions, +and government-guaranteed lending items in a single JSON datastore. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +from dataclasses import dataclass, asdict +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +EXCLUDED_DIR_NAMES = {".git", "node_modules", ".venv", "venv", "__pycache__"} +DEFAULT_DATASTORE = "objective_data.json" + + +@dataclass +class Submission: + objective_id: str + title: str + status: str + destination: str + due_date: str | None + notes: str | None + created_at: str + + +@dataclass +class LendingItem: + objective_id: str + borrower: str + amount: float + guarantee_type: str + status: str + reference: str | None + created_at: str + + +def now_iso() -> str: + return datetime.now(timezone.utc).isoformat() + + +def ensure_schema(data: dict[str, Any]) -> dict[str, Any]: + """Ensure datastore includes all required keys across versions.""" + data.setdefault("created_at", now_iso()) + data.setdefault("updated_at", now_iso()) + data.setdefault("objectives", {}) + data.setdefault("permissions", []) + data.setdefault("submissions", []) + data.setdefault("government_guarantee_lending", []) + data.setdefault("file_index", {}) + data.setdefault("objective_file_links", []) + data.setdefault("execution_steps", []) + data.setdefault("authority_control_matrix", []) + return data + + +class ObjectiveStore: + def __init__(self, path: Path) -> None: + self.path = path + self.data = self._load() + + def _load(self) -> dict[str, Any]: + if not self.path.exists(): + return ensure_schema({}) + + with self.path.open("r", encoding="utf-8") as handle: + return ensure_schema(json.load(handle)) + + def save(self) -> None: + self.data["updated_at"] = now_iso() + with self.path.open("w", encoding="utf-8") as handle: + json.dump(self.data, handle, indent=2, ensure_ascii=False) + + def add_objective(self, objective_id: str, summary: str, owner: str | None, status: str) -> None: + existing = self.data["objectives"].get(objective_id, {}) + created_at = existing.get("created_at", now_iso()) + self.data["objectives"][objective_id] = { + "summary": summary, + "owner": owner, + "status": status, + "created_at": created_at, + "updated_at": now_iso(), + } + + def add_permission(self, objective_id: str, granted_by: str, scope: str, expires_on: str | None) -> None: + self.data["permissions"].append( + { + "objective_id": objective_id, + "granted_by": granted_by, + "scope": scope, + "expires_on": expires_on, + "created_at": now_iso(), + } + ) + + def add_submission(self, submission: Submission) -> None: + self.data["submissions"].append(asdict(submission)) + + def add_lending_item(self, lending_item: LendingItem) -> None: + self.data["government_guarantee_lending"].append(asdict(lending_item)) + + def link_file( + self, + objective_id: str, + file_path: str, + situation: str, + target_location: str, + notes: str | None, + ) -> None: + self.data["objective_file_links"].append( + { + "objective_id": objective_id, + "file_path": file_path, + "situation": situation, + "target_location": target_location, + "notes": notes, + "created_at": now_iso(), + } + ) + + def rebuild_file_index(self, root: Path) -> int: + index: dict[str, Any] = {} + for path in root.rglob("*"): + if not path.is_file(): + continue + if any(part in EXCLUDED_DIR_NAMES for part in path.parts): + continue + + relative_path = str(path.relative_to(root)) + stats = path.stat() + index[relative_path] = { + "size_bytes": stats.st_size, + "modified_at": datetime.fromtimestamp(stats.st_mtime, tz=timezone.utc).isoformat(), + "sha256": file_hash(path), + } + + self.data["file_index"] = index + return len(index) + + def add_execution_step( + self, + objective_id: str, + step_id: str, + title: str, + status: str, + priority: int, + notes: str | None, + ) -> None: + self.data["execution_steps"] = [ + step + for step in self.data["execution_steps"] + if not (step["objective_id"] == objective_id and step["step_id"] == step_id) + ] + self.data["execution_steps"].append( + { + "objective_id": objective_id, + "step_id": step_id, + "title": title, + "status": status, + "priority": priority, + "notes": notes, + "updated_at": now_iso(), + } + ) + + def set_step_status(self, objective_id: str, step_id: str, status: str) -> None: + for step in self.data["execution_steps"]: + if step["objective_id"] == objective_id and step["step_id"] == step_id: + step["status"] = status + step["updated_at"] = now_iso() + return + raise SystemExit(f"Step '{step_id}' not found for objective '{objective_id}'.") + + def add_control_matrix( + self, + pon: str, + tas: str, + approval_authority: str, + execution_systems: str, + custody: str, + oversight: str, + notes: str | None, + ) -> None: + self.data["authority_control_matrix"].append( + { + "pon": pon, + "tas": tas, + "approval_authority": approval_authority, + "execution_systems": execution_systems, + "custody": custody, + "oversight": oversight, + "notes": notes, + "created_at": now_iso(), + } + ) + + def objective_snapshot(self, objective_id: str) -> dict[str, Any]: + validate_objective_exists(self, objective_id) + return { + "objective_id": objective_id, + "objective": self.data["objectives"][objective_id], + "permissions": [ + permission + for permission in self.data["permissions"] + if permission["objective_id"] == objective_id + ], + "submissions": [ + submission + for submission in self.data["submissions"] + if submission["objective_id"] == objective_id + ], + "government_guarantee_lending": [ + lending + for lending in self.data["government_guarantee_lending"] + if lending["objective_id"] == objective_id + ], + "file_links": [ + link + for link in self.data["objective_file_links"] + if link["objective_id"] == objective_id + ], + "execution_steps": sorted( + [ + step + for step in self.data["execution_steps"] + if step["objective_id"] == objective_id + ], + key=lambda item: (item["status"] != "in_progress", item["priority"]), + ), + } + + +def file_hash(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(8192), b""): + digest.update(chunk) + return digest.hexdigest() + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description=( + "Collect and organize objective data, permission records, file inventory, " + "submissions, and government-guaranteed lending entries." + ) + ) + parser.add_argument("--store", default=DEFAULT_DATASTORE, help="Path to datastore JSON") + subparsers = parser.add_subparsers(dest="command", required=True) + + add_objective = subparsers.add_parser("add-objective", help="Create or update an objective") + add_objective.add_argument("--id", required=True, help="Objective identifier") + add_objective.add_argument("--summary", required=True, help="Objective summary") + add_objective.add_argument("--owner", help="Objective owner") + add_objective.add_argument("--status", default="active", help="Objective status") + + add_permission = subparsers.add_parser("add-permission", help="Record a permission grant") + add_permission.add_argument("--objective", required=True, help="Objective identifier") + add_permission.add_argument("--granted-by", required=True, help="Authority granting permission") + add_permission.add_argument("--scope", required=True, help="Permission scope") + add_permission.add_argument("--expires-on", help="Optional expiration date (YYYY-MM-DD)") + + add_submission = subparsers.add_parser("add-submission", help="Record a submission") + add_submission.add_argument("--objective", required=True, help="Objective identifier") + add_submission.add_argument("--title", required=True, help="Submission title") + add_submission.add_argument("--status", required=True, help="Submission status") + add_submission.add_argument("--destination", required=True, help="Submission destination") + add_submission.add_argument("--due-date", help="Optional due date (YYYY-MM-DD)") + add_submission.add_argument("--notes", help="Optional notes") + + add_lending = subparsers.add_parser( + "add-lending-item", + help="Record government guarantee lending information", + ) + add_lending.add_argument("--objective", required=True, help="Objective identifier") + add_lending.add_argument("--borrower", required=True, help="Borrower organization") + add_lending.add_argument("--amount", required=True, type=float, help="Amount requested") + add_lending.add_argument("--guarantee-type", required=True, help="Guarantee type") + add_lending.add_argument("--status", required=True, help="Current status") + add_lending.add_argument("--reference", help="Optional external reference") + + add_execution_step = subparsers.add_parser( + "add-execution-step", + help="Add or update a progressive action step for an objective", + ) + add_execution_step.add_argument("--objective", required=True, help="Objective identifier") + add_execution_step.add_argument("--step-id", required=True, help="Stable step identifier") + add_execution_step.add_argument("--title", required=True, help="Step title") + add_execution_step.add_argument("--status", default="pending", help="Step status") + add_execution_step.add_argument("--priority", type=int, default=100, help="Lower number = higher priority") + add_execution_step.add_argument("--notes", help="Optional execution notes") + + update_step_status = subparsers.add_parser( + "update-step-status", + help="Update the status of an execution step", + ) + update_step_status.add_argument("--objective", required=True, help="Objective identifier") + update_step_status.add_argument("--step-id", required=True, help="Step identifier") + update_step_status.add_argument("--status", required=True, help="New step status") + + control_matrix = subparsers.add_parser( + "add-control-matrix", + help="Record authority and control matrix metadata", + ) + control_matrix.add_argument("--pon", required=True, help="Program office number") + control_matrix.add_argument("--tas", required=True, help="Treasury account symbol") + control_matrix.add_argument("--approval-authority", required=True, help="Approval authority") + control_matrix.add_argument("--execution-systems", required=True, help="Authorized execution systems") + control_matrix.add_argument("--custody", required=True, help="Custody authority") + control_matrix.add_argument("--oversight", required=True, help="Oversight authorities") + control_matrix.add_argument("--notes", help="Optional notes") + + link_file = subparsers.add_parser( + "link-file", + help="Link a file to an objective and situation for placement/organization", + ) + link_file.add_argument("--objective", required=True, help="Objective identifier") + link_file.add_argument("--file-path", required=True, help="Indexed file path") + link_file.add_argument("--situation", required=True, help="Context or situation for this file") + link_file.add_argument("--target-location", required=True, help="Where this file should be placed") + link_file.add_argument("--notes", help="Optional notes") + + index_files = subparsers.add_parser("index-files", help="Rebuild file inventory") + index_files.add_argument("--root", default=".", help="Root directory to scan") + + get_all_data = subparsers.add_parser("get-all-data", help="Print full datastore JSON") + get_all_data.add_argument("--objective", help="Optional objective id to filter output") + + organize_plan = subparsers.add_parser( + "organize-plan", + help="Print file placement plan grouped by target location", + ) + organize_plan.add_argument("--objective", required=True, help="Objective identifier") + + subparsers.add_parser("summary", help="Print dataset summary") + + return parser.parse_args() + + +def validate_objective_exists(store: ObjectiveStore, objective_id: str) -> None: + if objective_id not in store.data["objectives"]: + raise SystemExit(f"Objective '{objective_id}' does not exist. Add it first with add-objective.") + + +def print_summary(store: ObjectiveStore) -> None: + print("Datastore:", store.path) + print("Objectives:", len(store.data["objectives"])) + print("Permissions:", len(store.data["permissions"])) + print("Submissions:", len(store.data["submissions"])) + print("Government guarantee lending items:", len(store.data["government_guarantee_lending"])) + print("Indexed files:", len(store.data["file_index"])) + print("Linked files:", len(store.data["objective_file_links"])) + print("Execution steps:", len(store.data["execution_steps"])) + print("Authority/control records:", len(store.data["authority_control_matrix"])) + + +def print_json(payload: dict[str, Any]) -> None: + print(json.dumps(payload, indent=2, ensure_ascii=False)) + + +def print_organize_plan(store: ObjectiveStore, objective_id: str) -> None: + snapshot = store.objective_snapshot(objective_id) + grouped: dict[str, list[dict[str, Any]]] = {} + for link in snapshot["file_links"]: + target = link["target_location"] + entry = { + "file_path": link["file_path"], + "situation": link["situation"], + "notes": link["notes"], + "indexed": link["file_path"] in store.data["file_index"], + } + grouped.setdefault(target, []).append(entry) + + print_json( + { + "objective_id": objective_id, + "target_locations": grouped, + "steps": snapshot["execution_steps"], + } + ) + + +def main() -> None: + args = parse_args() + store = ObjectiveStore(Path(args.store)) + + if args.command == "add-objective": + store.add_objective(objective_id=args.id, summary=args.summary, owner=args.owner, status=args.status) + store.save() + print(f"Objective '{args.id}' saved.") + return + + if args.command == "add-permission": + validate_objective_exists(store, args.objective) + store.add_permission( + objective_id=args.objective, + granted_by=args.granted_by, + scope=args.scope, + expires_on=args.expires_on, + ) + store.save() + print("Permission saved.") + return + + if args.command == "add-submission": + validate_objective_exists(store, args.objective) + submission = Submission( + objective_id=args.objective, + title=args.title, + status=args.status, + destination=args.destination, + due_date=args.due_date, + notes=args.notes, + created_at=now_iso(), + ) + store.add_submission(submission) + store.save() + print("Submission saved.") + return + + if args.command == "add-lending-item": + validate_objective_exists(store, args.objective) + lending_item = LendingItem( + objective_id=args.objective, + borrower=args.borrower, + amount=args.amount, + guarantee_type=args.guarantee_type, + status=args.status, + reference=args.reference, + created_at=now_iso(), + ) + store.add_lending_item(lending_item) + store.save() + print("Lending item saved.") + return + + if args.command == "add-execution-step": + validate_objective_exists(store, args.objective) + store.add_execution_step( + objective_id=args.objective, + step_id=args.step_id, + title=args.title, + status=args.status, + priority=args.priority, + notes=args.notes, + ) + store.save() + print("Execution step saved.") + return + + if args.command == "update-step-status": + validate_objective_exists(store, args.objective) + store.set_step_status( + objective_id=args.objective, + step_id=args.step_id, + status=args.status, + ) + store.save() + print("Execution step status updated.") + return + + if args.command == "add-control-matrix": + store.add_control_matrix( + pon=args.pon, + tas=args.tas, + approval_authority=args.approval_authority, + execution_systems=args.execution_systems, + custody=args.custody, + oversight=args.oversight, + notes=args.notes, + ) + store.save() + print("Authority/control matrix record saved.") + return + + if args.command == "link-file": + validate_objective_exists(store, args.objective) + store.link_file( + objective_id=args.objective, + file_path=args.file_path, + situation=args.situation, + target_location=args.target_location, + notes=args.notes, + ) + store.save() + print("File link saved.") + return + + if args.command == "index-files": + count = store.rebuild_file_index(Path(args.root).resolve()) + store.save() + print(f"Indexed {count} files.") + return + + if args.command == "get-all-data": + if args.objective: + print_json(store.objective_snapshot(args.objective)) + return + print_json(store.data) + return + + if args.command == "organize-plan": + print_organize_plan(store, args.objective) + return + + if args.command == "summary": + print_summary(store) + + +if __name__ == "__main__": + main()